Port latest features from test client to extension
This commit is contained in:
		
							parent
							
								
									c88ae7d972
								
							
						
					
					
						commit
						2706b7f628
					
				@ -17,12 +17,16 @@ def BuildEverything():
 | 
				
			|||||||
	compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'public', 'extensions'))
 | 
						compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'public', 'extensions'))
 | 
				
			||||||
	compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'public', 'sourcepawn'))
 | 
						compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'public', 'sourcepawn'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if AMBuild.target['platform'] in ['linux']:
 | 
						if AMBuild.target['platform'] in ['linux']:
 | 
				
			||||||
 | 
							compiler['POSTLINKFLAGS'].append('-lm')
 | 
				
			||||||
		compiler['POSTLINKFLAGS'].append('-lstdc++')
 | 
							compiler['POSTLINKFLAGS'].append('-lstdc++')
 | 
				
			||||||
		compiler['POSTLINKFLAGS'].append('-pthread')
 | 
							compiler['POSTLINKFLAGS'].append('-pthread')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							compiler['CDEFINES'].append('HAVE_CONFIG_H')
 | 
				
			||||||
 | 
							compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'build', 'src'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	name = 'accelerator.ext'
 | 
						name = 'accelerator.ext'
 | 
				
			||||||
	extension = AMBuild.AddJob(name)
 | 
						extension = AMBuild.AddJob(name)
 | 
				
			||||||
	binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler)
 | 
						binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler)
 | 
				
			||||||
@ -34,28 +38,55 @@ def BuildEverything():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	binary.AddSourceFiles(AMBuild.cache['SOURCEMOD'], ['public/smsdk_ext.cpp'])
 | 
						binary.AddSourceFiles(AMBuild.cache['SOURCEMOD'], ['public/smsdk_ext.cpp'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if AMBuild.target['platform'] in ['linux']:
 | 
				
			||||||
 | 
					            binary.AddSourceFiles(os.path.join('breakpad', 'src', 'src', 'common'), [
 | 
				
			||||||
 | 
					                'dwarf_cfi_to_module.cc',
 | 
				
			||||||
 | 
					                'dwarf_cu_to_module.cc',
 | 
				
			||||||
 | 
					                'dwarf_line_to_module.cc',
 | 
				
			||||||
 | 
					                'language.cc',
 | 
				
			||||||
 | 
					                'module.cc',
 | 
				
			||||||
 | 
					                'path_helper.cc',
 | 
				
			||||||
 | 
					                'stabs_reader.cc',
 | 
				
			||||||
 | 
					                'stabs_to_module.cc',
 | 
				
			||||||
 | 
					                'dwarf/bytereader.cc',
 | 
				
			||||||
 | 
					                'dwarf/dwarf2diehandler.cc',
 | 
				
			||||||
 | 
					                'dwarf/dwarf2reader.cc',
 | 
				
			||||||
 | 
					                'dwarf/elf_reader.cc',
 | 
				
			||||||
 | 
					                'linux/crc32.cc',
 | 
				
			||||||
 | 
					                'linux/dump_symbols.cc',
 | 
				
			||||||
 | 
					                'linux/elf_symbols_to_module.cc',
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if AMBuild.target['platform'] in ['linux']:
 | 
						if AMBuild.target['platform'] in ['linux']:
 | 
				
			||||||
		link = os.path.join(AMBuild.outputFolder, extension.workFolder, 'libbreakpad_client.a')
 | 
							libs = [
 | 
				
			||||||
		target = os.path.join(AMBuild.sourceFolder, 'breakpad', 'build', 'src', 'client', 'linux', 'libbreakpad_client.a')
 | 
								('libbreakpad_client.a', os.path.join('breakpad', 'build', 'src', 'client', 'linux', 'libbreakpad_client.a')),
 | 
				
			||||||
		try:
 | 
								('libbreakpad.a', os.path.join('breakpad', 'build', 'src', 'libbreakpad.a')),
 | 
				
			||||||
			os.lstat(link)
 | 
								('libdisasm.a', os.path.join('breakpad', 'build', 'src', 'third_party', 'libdisasm', 'libdisasm.a')),
 | 
				
			||||||
		except:
 | 
							]
 | 
				
			||||||
			extension.AddCommand(SymlinkCommand(link, target))
 | 
					
 | 
				
			||||||
		binary.AddObjectFiles(['libbreakpad_client.a'])
 | 
							for lib, target in libs:
 | 
				
			||||||
 | 
								link = os.path.join(AMBuild.outputFolder, extension.workFolder, lib)
 | 
				
			||||||
 | 
								target = os.path.join(AMBuild.sourceFolder, target)
 | 
				
			||||||
 | 
								try:
 | 
				
			||||||
 | 
									os.lstat(link)
 | 
				
			||||||
 | 
								except:
 | 
				
			||||||
 | 
									extension.AddCommand(SymlinkCommand(link, target))
 | 
				
			||||||
 | 
								binary.AddObjectFiles([lib])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elif AMBuild.target['platform'] in ['windows']:
 | 
						elif AMBuild.target['platform'] in ['windows']:
 | 
				
			||||||
		libs = ['exception_handler', 'common']
 | 
							libs = [
 | 
				
			||||||
		for lib in libs:
 | 
							    os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', 'common.lib'),
 | 
				
			||||||
			path = os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', lib + '.lib')
 | 
							    os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', 'exception_handler.lib'),
 | 
				
			||||||
 | 
							    os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'crash_generation', 'Release', 'lib', 'crash_generation_client.lib'),
 | 
				
			||||||
 | 
							    os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'processor', 'Release', 'lib', 'libdisasm.lib'),
 | 
				
			||||||
 | 
							    os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'processor', 'Release', 'lib', 'processor.lib'),
 | 
				
			||||||
 | 
							]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for path in libs:
 | 
				
			||||||
			if os.path.isfile(path):
 | 
								if os.path.isfile(path):
 | 
				
			||||||
				binary.RelinkIfNewer(path)
 | 
									binary.RelinkIfNewer(path)
 | 
				
			||||||
			binary['POSTLINKFLAGS'].extend([path])
 | 
								binary['POSTLINKFLAGS'].extend([path])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		path = os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'crash_generation', 'Release', 'lib', 'crash_generation_client.lib')
 | 
					 | 
				
			||||||
		if os.path.isfile(path):
 | 
					 | 
				
			||||||
			binary.RelinkIfNewer(path)
 | 
					 | 
				
			||||||
		binary['POSTLINKFLAGS'].extend([path])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SM.AutoVersion('extension', binary)
 | 
						SM.AutoVersion('extension', binary)
 | 
				
			||||||
	SM.ExtractDebugInfo(extension, binary)
 | 
						SM.ExtractDebugInfo(extension, binary)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -26,17 +26,52 @@
 | 
				
			|||||||
#include "client/linux/handler/exception_handler.h"
 | 
					#include "client/linux/handler/exception_handler.h"
 | 
				
			||||||
#include "common/linux/linux_libc_support.h"
 | 
					#include "common/linux/linux_libc_support.h"
 | 
				
			||||||
#include "third_party/lss/linux_syscall_support.h"
 | 
					#include "third_party/lss/linux_syscall_support.h"
 | 
				
			||||||
 | 
					#include "common/linux/dump_symbols.h"
 | 
				
			||||||
 | 
					#include "common/path_helper.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <signal.h>
 | 
					#include <signal.h>
 | 
				
			||||||
#include <dirent.h>
 | 
					#include <dirent.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <paths.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StderrInhibitor
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FILE *saved_stderr = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						StderrInhibitor() {
 | 
				
			||||||
 | 
							saved_stderr = fdopen(dup(fileno(stderr)), "w");
 | 
				
			||||||
 | 
							if (freopen(_PATH_DEVNULL, "w", stderr)) {
 | 
				
			||||||
 | 
								// If it fails, not a lot we can (or should) do.
 | 
				
			||||||
 | 
								// Add this brace section to silence gcc warnings.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~StderrInhibitor() {
 | 
				
			||||||
 | 
							fflush(stderr);
 | 
				
			||||||
 | 
							dup2(fileno(saved_stderr), fileno(stderr));
 | 
				
			||||||
 | 
							fclose(saved_stderr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined _WINDOWS
 | 
					#elif defined _WINDOWS
 | 
				
			||||||
#define _STDINT // ~.~
 | 
					#define _STDINT // ~.~
 | 
				
			||||||
#include "client/windows/handler/exception_handler.h"
 | 
					#include "client/windows/handler/exception_handler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#error Bad platform.
 | 
					#error Bad platform.
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <google_breakpad/processor/minidump.h>
 | 
				
			||||||
 | 
					#include <google_breakpad/processor/minidump_processor.h>
 | 
				
			||||||
 | 
					#include <google_breakpad/processor/process_state.h>
 | 
				
			||||||
 | 
					#include <google_breakpad/processor/call_stack.h>
 | 
				
			||||||
 | 
					#include <google_breakpad/processor/stack_frame.h>
 | 
				
			||||||
 | 
					#include <processor/pathname_stripper.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <streambuf>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Accelerator g_accelerator;
 | 
					Accelerator g_accelerator;
 | 
				
			||||||
SMEXT_LINK(&g_accelerator);
 | 
					SMEXT_LINK(&g_accelerator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -219,6 +254,7 @@ void OnGameFrame(bool simulating)
 | 
				
			|||||||
		sigaction(kExceptionSignals[i], &act, NULL);
 | 
							sigaction(kExceptionSignals[i], &act, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined _WINDOWS
 | 
					#elif defined _WINDOWS
 | 
				
			||||||
void *vectoredHandler = NULL;
 | 
					void *vectoredHandler = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -307,56 +343,25 @@ static bool dumpCallback(const wchar_t* dump_path,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return succeeded;
 | 
						return succeeded;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#error Bad platform.
 | 
					#error Bad platform.
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool UploadAndDeleteCrashDump(const char *path, char *response, int maxlen)
 | 
					class ClogInhibitor
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	IWebForm *form = webternet->CreateForm();
 | 
						std::streambuf *saved_clog = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
 | 
					public:
 | 
				
			||||||
	if (minidumpAccount) form->AddString("UserID", minidumpAccount);
 | 
						ClogInhibitor() {
 | 
				
			||||||
 | 
							saved_clog = std::clog.rdbuf();
 | 
				
			||||||
	form->AddString("GameDirectory", g_pSM->GetGameFolderName());
 | 
							std::clog.rdbuf(nullptr);
 | 
				
			||||||
	form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	form->AddFile("upload_file_minidump", path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char metapath[512];
 | 
					 | 
				
			||||||
	g_pSM->Format(metapath, sizeof(metapath), "%s.txt", path);
 | 
					 | 
				
			||||||
	if (libsys->PathExists(metapath)) {
 | 
					 | 
				
			||||||
		form->AddFile("upload_file_metadata", metapath);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MemoryDownloader data;
 | 
						~ClogInhibitor() {
 | 
				
			||||||
	IWebTransfer *xfer = webternet->CreateSession();
 | 
							std::clog.rdbuf(saved_clog);
 | 
				
			||||||
	xfer->SetFailOnHTTPError(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const char *minidumpUrl = g_pSM->GetCoreConfigValue("MinidumpUrl");
 | 
					 | 
				
			||||||
	if (!minidumpUrl) minidumpUrl = "http://crash.limetech.org/submit";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool uploaded = xfer->PostAndDownload(minidumpUrl, form, &data, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (response) {
 | 
					 | 
				
			||||||
		if (uploaded) {
 | 
					 | 
				
			||||||
			int responseSize = data.GetSize();
 | 
					 | 
				
			||||||
			if (responseSize >= maxlen) responseSize = maxlen - 1;
 | 
					 | 
				
			||||||
			strncpy(response, data.GetBuffer(), responseSize);
 | 
					 | 
				
			||||||
			response[responseSize] = '\0';
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			g_pSM->Format(response, maxlen, "%s (%d)", xfer->LastErrorMessage(), xfer->LastErrorCode());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
	if (libsys->PathExists(metapath)) {
 | 
					 | 
				
			||||||
		unlink(metapath);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unlink(path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return uploaded;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UploadThread: public IThread
 | 
					class UploadThread: public IThread
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -390,6 +395,10 @@ class UploadThread: public IThread
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			g_pSM->Format(path, sizeof(path), "%s/%s", dumpStoragePath, name);
 | 
								g_pSM->Format(path, sizeof(path), "%s/%s", dumpStoragePath, name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// TODO: Check the return value.
 | 
				
			||||||
 | 
								bool wantsUpload = PresubmitCrashDump(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			bool uploaded = UploadAndDeleteCrashDump(path, response, sizeof(response));
 | 
								bool uploaded = UploadAndDeleteCrashDump(path, response, sizeof(response));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (uploaded) {
 | 
								if (uploaded) {
 | 
				
			||||||
@ -418,6 +427,243 @@ class UploadThread: public IThread
 | 
				
			|||||||
		rootconsole->ConsolePrint("Accelerator upload thread terminated. (canceled = %s)", (cancel ? "true" : "false"));
 | 
							rootconsole->ConsolePrint("Accelerator upload thread terminated. (canceled = %s)", (cancel ? "true" : "false"));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool PresubmitCrashDump(const char *path) {
 | 
				
			||||||
 | 
							google_breakpad::ProcessState processState;
 | 
				
			||||||
 | 
							google_breakpad::ProcessResult processResult;
 | 
				
			||||||
 | 
							google_breakpad::MinidumpProcessor minidumpProcessor(nullptr, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ClogInhibitor clogInhibitor;
 | 
				
			||||||
 | 
								processResult = minidumpProcessor.Process(path, &processState);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (processResult != google_breakpad::PROCESS_OK) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int requestingThread = processState.requesting_thread();
 | 
				
			||||||
 | 
							if (requestingThread == -1) {
 | 
				
			||||||
 | 
								requestingThread = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const google_breakpad::CallStack *stack = processState.threads()->at(requestingThread);
 | 
				
			||||||
 | 
							if (!stack) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int frameCount = stack->frames()->size();
 | 
				
			||||||
 | 
							/*if (frameCount > 10) {
 | 
				
			||||||
 | 
								frameCount = 10;
 | 
				
			||||||
 | 
							}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::ostringstream summaryStream;
 | 
				
			||||||
 | 
							summaryStream << 1 << "|" << processState.crashed() << "|" << processState.crash_reason() << "|" << std::hex << processState.crash_address() << std::dec << "|" << requestingThread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::map<const google_breakpad::CodeModule *, unsigned int> moduleMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							unsigned int moduleCount = processState.modules()->module_count();
 | 
				
			||||||
 | 
							for (unsigned int moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) {
 | 
				
			||||||
 | 
								auto module = processState.modules()->GetModuleAtIndex(moduleIndex);
 | 
				
			||||||
 | 
								moduleMap[module] = moduleIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto debugFile = google_breakpad::PathnameStripper::File(module->debug_file());
 | 
				
			||||||
 | 
								auto debugIdentifier = module->debug_identifier();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								summaryStream << "|M|" << debugFile << "|" << debugIdentifier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
 | 
				
			||||||
 | 
								auto frame = stack->frames()->at(frameIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int moduleIndex = -1;
 | 
				
			||||||
 | 
								auto moduleOffset = frame->ReturnAddress();
 | 
				
			||||||
 | 
								if (frame->module) {
 | 
				
			||||||
 | 
									moduleIndex = moduleMap[frame->module];
 | 
				
			||||||
 | 
									moduleOffset -= frame->module->base_address();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								summaryStream << "|F|" << moduleIndex << "|" << std::hex << moduleOffset << std::dec;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto summaryLine = summaryStream.str();
 | 
				
			||||||
 | 
							// printf("%s\n", summaryLine.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IWebForm *form = webternet->CreateForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
 | 
				
			||||||
 | 
							if (minidumpAccount) form->AddString("UserID", minidumpAccount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							form->AddString("CrashSignature", summaryLine.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							MemoryDownloader data;
 | 
				
			||||||
 | 
							IWebTransfer *xfer = webternet->CreateSession();
 | 
				
			||||||
 | 
							xfer->SetFailOnHTTPError(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const char *minidumpUrl = g_pSM->GetCoreConfigValue("MinidumpUrl");
 | 
				
			||||||
 | 
							if (!minidumpUrl) minidumpUrl = "http://crash.limetech.org/submit";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool uploaded = xfer->PostAndDownload(minidumpUrl, form, &data, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!uploaded) {
 | 
				
			||||||
 | 
								printf(">>> Presubmit failed: %s (%d)\n", xfer->LastErrorMessage(), xfer->LastErrorCode());
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int responseSize = data.GetSize();
 | 
				
			||||||
 | 
							char *response = new char[responseSize + 1];
 | 
				
			||||||
 | 
							strncpy(response, data.GetBuffer(), responseSize + 1);
 | 
				
			||||||
 | 
							response[responseSize] = '\0';
 | 
				
			||||||
 | 
							printf(">>> Presubmit complete: %s\n", response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (responseSize < 2) {
 | 
				
			||||||
 | 
								printf(">>> Response too short\n");
 | 
				
			||||||
 | 
								delete[] response;
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (response[0] == 'E') {
 | 
				
			||||||
 | 
								printf(">>> Presubmit error: %s\n", &response[2]);
 | 
				
			||||||
 | 
								delete[] response;
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool submitCrash = (response[0] == 'Y');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (response[1] != '|') {
 | 
				
			||||||
 | 
								printf(">>> Response delimiter missing\n");
 | 
				
			||||||
 | 
								delete[] response;
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							unsigned int responseCount = responseSize - 2;
 | 
				
			||||||
 | 
							if (responseCount != moduleCount) {
 | 
				
			||||||
 | 
								printf(">>> Response module list doesn't match sent list (%d != %d)\n", responseCount, moduleCount);
 | 
				
			||||||
 | 
								delete[] response;
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined _LINUX
 | 
				
			||||||
 | 
							for (unsigned int moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) {
 | 
				
			||||||
 | 
								bool submitModule = (response[2 + moduleIndex] == 'Y');
 | 
				
			||||||
 | 
								if (!submitModule) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto module = processState.modules()->GetModuleAtIndex(moduleIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto debugFile = module->debug_file();
 | 
				
			||||||
 | 
								if (debugFile[0] != '/') {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								printf(">>> Submitting %s\n", debugFile.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto debugFileDir = google_breakpad::DirName(debugFile);
 | 
				
			||||||
 | 
								std::vector<string> debug_dirs{
 | 
				
			||||||
 | 
									debugFileDir,
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								std::ostringstream outputStream;
 | 
				
			||||||
 | 
								google_breakpad::DumpOptions options(ALL_SYMBOL_DATA, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									StderrInhibitor stdrrInhibitor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!WriteSymbolFile(debugFile, debug_dirs, options, outputStream)) {
 | 
				
			||||||
 | 
										outputStream.str("");
 | 
				
			||||||
 | 
										outputStream.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// Try again without debug dirs.
 | 
				
			||||||
 | 
										if (!WriteSymbolFile(debugFile, {}, options, outputStream)) {
 | 
				
			||||||
 | 
											// TODO: Something.
 | 
				
			||||||
 | 
											continue;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto output = outputStream.str();
 | 
				
			||||||
 | 
								// output = output.substr(0, output.find("\n"));
 | 
				
			||||||
 | 
								// printf(">>> %s\n", output.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								IWebForm *symbolForm = webternet->CreateForm();
 | 
				
			||||||
 | 
								symbolForm->AddString("symbol_file", output.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								MemoryDownloader symbolData;
 | 
				
			||||||
 | 
								IWebTransfer *symbolXfer = webternet->CreateSession();
 | 
				
			||||||
 | 
								xfer->SetFailOnHTTPError(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const char *symbolUrl = g_pSM->GetCoreConfigValue("MinidumpSymbolUrl");
 | 
				
			||||||
 | 
								if (!symbolUrl) symbolUrl = "http://crash.limetech.org/symbols/submit";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bool symbolUploaded = symbolXfer->PostAndDownload(symbolUrl, symbolForm, &symbolData, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!symbolUploaded) {
 | 
				
			||||||
 | 
									printf(">>> Symbol upload failed: %s (%d)\n", symbolXfer->LastErrorMessage(), symbolXfer->LastErrorCode());
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int symbolResponseSize = symbolData.GetSize();
 | 
				
			||||||
 | 
								char *symbolResponse = new char[symbolResponseSize + 1];
 | 
				
			||||||
 | 
								strncpy(symbolResponse, symbolData.GetBuffer(), symbolResponseSize + 1);
 | 
				
			||||||
 | 
								do {
 | 
				
			||||||
 | 
									symbolResponse[symbolResponseSize] = '\0';
 | 
				
			||||||
 | 
								} while (symbolResponse[--symbolResponseSize] == '\n');
 | 
				
			||||||
 | 
								printf(">>> Symbol upload complete: %s\n", symbolResponse);
 | 
				
			||||||
 | 
								delete[] symbolResponse;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							printf(">>> Symbol submission not available on this platform\n");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							delete[] response;
 | 
				
			||||||
 | 
							return submitCrash;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool UploadAndDeleteCrashDump(const char *path, char *response, int maxlen) {
 | 
				
			||||||
 | 
							IWebForm *form = webternet->CreateForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const char *minidumpAccount = g_pSM->GetCoreConfigValue("MinidumpAccount");
 | 
				
			||||||
 | 
							if (minidumpAccount) form->AddString("UserID", minidumpAccount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							form->AddString("GameDirectory", g_pSM->GetGameFolderName());
 | 
				
			||||||
 | 
							form->AddString("ExtensionVersion", SMEXT_CONF_VERSION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							form->AddFile("upload_file_minidump", path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							char metapath[512];
 | 
				
			||||||
 | 
							g_pSM->Format(metapath, sizeof(metapath), "%s.txt", path);
 | 
				
			||||||
 | 
							if (libsys->PathExists(metapath)) {
 | 
				
			||||||
 | 
								form->AddFile("upload_file_metadata", metapath);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							MemoryDownloader data;
 | 
				
			||||||
 | 
							IWebTransfer *xfer = webternet->CreateSession();
 | 
				
			||||||
 | 
							xfer->SetFailOnHTTPError(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const char *minidumpUrl = g_pSM->GetCoreConfigValue("MinidumpUrl");
 | 
				
			||||||
 | 
							if (!minidumpUrl) minidumpUrl = "http://crash.limetech.org/submit";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool uploaded = xfer->PostAndDownload(minidumpUrl, form, &data, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (response) {
 | 
				
			||||||
 | 
								if (uploaded) {
 | 
				
			||||||
 | 
									int responseSize = data.GetSize();
 | 
				
			||||||
 | 
									if (responseSize >= maxlen) responseSize = maxlen - 1;
 | 
				
			||||||
 | 
									strncpy(response, data.GetBuffer(), responseSize);
 | 
				
			||||||
 | 
									response[responseSize] = '\0';
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									g_pSM->Format(response, maxlen, "%s (%d)", xfer->LastErrorMessage(), xfer->LastErrorCode());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (libsys->PathExists(metapath)) {
 | 
				
			||||||
 | 
								unlink(metapath);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							unlink(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return uploaded;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
} uploadThread;
 | 
					} uploadThread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VFuncEmptyClass {};
 | 
					class VFuncEmptyClass {};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user