From 0f4405dbaf93e9cb9397b03a950c8a58c6e88a06 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 21 Jan 2016 14:58:58 +0800
Subject: [PATCH] backtrace output for win platform added, testing with abort()
 call in ~AppClass()

---
 Telegram/SourceFiles/application.cpp   |  39 ++-
 Telegram/SourceFiles/facades.cpp       |   3 +
 Telegram/SourceFiles/facades.h         |   1 +
 Telegram/SourceFiles/logs.cpp          | 149 +++++++++++-
 Telegram/SourceFiles/logs.h            |  19 ++
 Telegram/SourceFiles/main.cpp          |   1 +
 Telegram/SourceFiles/pspecific_wnd.cpp | 318 ++++++++++++++++++++++++-
 Telegram/SourceFiles/pspecific_wnd.h   |   2 +
 Telegram/SourceFiles/stdafx.h          |   2 +
 Telegram/SourceFiles/types.cpp         |  43 ----
 Telegram/SourceFiles/types.h           |   2 -
 11 files changed, 507 insertions(+), 72 deletions(-)

diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp
index 686db06b7..d8137a113 100644
--- a/Telegram/SourceFiles/application.cpp
+++ b/Telegram/SourceFiles/application.cpp
@@ -231,6 +231,8 @@ void Application::socketReading() {
 }
 
 void Application::socketError(QLocalSocket::LocalSocketError e) {
+	if (App::quiting()) return;
+
 	if (_secondInstance) {
 		LOG(("Could not write show command, error %1, quiting..").arg(e));
 		return App::quit();
@@ -265,18 +267,33 @@ void Application::singleInstanceChecked() {
 	if (cManyInstance()) {
 		Logs::multipleInstances();
 	}
-	if ((!cManyInstance() && !Logs::instanceChecked()) || !Logs::started()) {
-		MessageBox(0, (QString::fromStdWString(L"Could not initialize logs!\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR);
-		// show error window
-		App::quit();
-		return;
-	}
 
 	Global::start();
 
-	// if crashed, show window and try to autoupdate
-
-	new AppClass();
+	if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) {
+		// show error window
+		MessageBox(0, (QString::fromStdWString(L"Could not start Telegram Dekstop! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR);
+		App::quit();
+	} else {
+		SignalHandlers::Status status = SignalHandlers::start();
+		if (status == SignalHandlers::CantOpen) {
+			// show error window
+			MessageBox(0, (QString::fromStdWString(L"Could not start Telegram Dekstop! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR);
+			App::quit();
+		} else {
+			if (status == SignalHandlers::LastCrashed) {
+				// show error window
+				MessageBox(0, (QString::fromStdWString(L"Last time Telegram Dekstop crashed! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR);
+				if (SignalHandlers::restart() == SignalHandlers::CantOpen) {
+					// show error window
+					MessageBox(0, (QString::fromStdWString(L"Could not start Telegram Dekstop! Log:\n\n") + Logs::full()).toStdWString().c_str(), L"Error!", MB_ICONERROR);
+					App::quit();
+					return;
+				}
+			}
+			new AppClass();
+		}
+	}
 }
 
 void Application::socketDisconnected() {
@@ -638,8 +655,6 @@ AppClass::AppClass() : QObject()
 , _uploader(0) {
 	AppObject = this;
 
-	installSignalHandlers();
-
 	ThirdParty::start();
 	Sandbox::start();
 	Local::start();
@@ -1035,6 +1050,8 @@ void AppClass::execExternal(const QString &cmd) {
 }
 
 AppClass::~AppClass() {
+	abort();
+
 	_window.setParent(0);
 
 	anim::stopManager();
diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp
index 1be6560e1..2c3fd675f 100644
--- a/Telegram/SourceFiles/facades.cpp
+++ b/Telegram/SourceFiles/facades.cpp
@@ -179,6 +179,8 @@ namespace Notify {
 struct GlobalDataStruct {
 	QString LangSystemISO;
 	int32 LangSystem = languageDefault;
+
+	QByteArray LastCrashDump;
 };
 GlobalDataStruct *GlobalData = 0;
 
@@ -278,6 +280,7 @@ Type &Ref##Name() { \
 
 	DefineGlobalReadOnly(QString, LangSystemISO);
 	DefineGlobalReadOnly(int32, LangSystem);
+	DefineGlobal(QByteArray, LastCrashDump);
 
 }
 
diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h
index 70749a67f..e86c125d9 100644
--- a/Telegram/SourceFiles/facades.h
+++ b/Telegram/SourceFiles/facades.h
@@ -111,6 +111,7 @@ namespace Global {
 
 	DeclareGlobalReadOnly(QString, LangSystemISO);
 	DeclareGlobalReadOnly(int32, LangSystem);
+	DeclareGlobal(QByteArray, LastCrashDump);
 
 }
 
diff --git a/Telegram/SourceFiles/logs.cpp b/Telegram/SourceFiles/logs.cpp
index d957bdd13..4869f079d 100644
--- a/Telegram/SourceFiles/logs.cpp
+++ b/Telegram/SourceFiles/logs.cpp
@@ -267,13 +267,11 @@ namespace Logs {
 		}
 		bool workingDirChosen = cBetaVersion();
 
-		QString moveOldDataFrom;
+		QString initialWorkingDir = QDir(cWorkingDir()).absolutePath() + '/', moveOldDataFrom;
 		if (cBetaVersion()) {
 			cSetDebug(true);
 #if (defined Q_OS_MAC || defined Q_OS_LINUX)
 		} else {
-			QString wasDir = QDir(cWorkingDir()).absolutePath() + '/';
-
 #ifdef _DEBUG
 			cForceWorkingDir(cExeDir());
 #else
@@ -284,7 +282,7 @@ namespace Logs {
 			workingDirChosen = true;
 
 #if (defined Q_OS_LINUX && !defined _DEBUG) // fix first version
-			moveOldDataFrom = wasDir;
+			moveOldDataFrom = initialWorkingDir;
 #endif
 
 #endif
@@ -303,17 +301,22 @@ namespace Logs {
 
 		cForceWorkingDir(QDir(cWorkingDir()).absolutePath() + '/');
 		QDir().setCurrent(cWorkingDir());
+		QDir().mkpath(cWorkingDir() + qstr("tdata"));
 
 		Global::WorkingDirReady();
 
-		LOG(("Launched version: %1, dev: %2, beta: %3, debug mode: %4, test dc: %5").arg(AppVersion).arg(Logs::b(cDevVersion())).arg(cBetaVersion()).arg(Logs::b(cDebug())).arg(Logs::b(cTestMode())));
-		LOG(("Executable dir: %1, name: %2").arg(cExeDir()).arg(cExeName()));
-		LOG(("Working dir: %1").arg(cWorkingDir()));
-		LOG(("Arguments: %1").arg(cArguments()));
-
 		if (!LogsData->openMain()) {
 			delete LogsData;
 			LogsData = 0;
+		}
+
+		LOG(("Launched version: %1, dev: %2, beta: %3, debug mode: %4, test dc: %5").arg(AppVersion).arg(Logs::b(cDevVersion())).arg(cBetaVersion()).arg(Logs::b(cDebug())).arg(Logs::b(cTestMode())));
+		LOG(("Executable dir: %1, name: %2").arg(cExeDir()).arg(cExeName()));
+		LOG(("Initial working dir: %1").arg(initialWorkingDir));
+		LOG(("Working dir: %1").arg(cWorkingDir()));
+		LOG(("Arguments: %1").arg(cArguments()));
+
+		if (!LogsData) {
 			LOG(("Could not open '%1' for writing log!").arg(_logsFilePath(LogDataMain, qsl("_startXX"))));
 			return;
 		}
@@ -333,11 +336,12 @@ namespace Logs {
 			for (LogsInMemoryList::const_iterator i = list.cbegin(), e = list.cend(); i != e; ++i) {
 				if (i->first == LogDataMain) {
 					_logsWrite(i->first, i->second);
+					LOG(("First: %1, %2").arg(i->first).arg(i->second));
 				}
 			}
 		}
 
-		LOG(("Logs started."));
+		LOG(("Logs started"));
 	}
 
 	Initializer::~Initializer() {
@@ -368,6 +372,8 @@ namespace Logs {
 			return false;
 		}
 
+
+
 		if (LogsInMemory) {
 			t_assert(LogsInMemory != DeletedLogsInMemory);
 			LogsInMemoryList list = *LogsInMemory;
@@ -539,3 +545,126 @@ void _moveOldDataFiles(const QString &wasDir) {
 		}
 	}
 }
+
+namespace SignalHandlers {
+
+	QByteArray CrashDumpPath;
+	FILE *CrashDumpFile = 0;
+	int CrashDumpFileNo = 0;
+
+	void _writeChar(char ch) {
+		fwrite(&ch, 1, 1, CrashDumpFile);
+	}
+
+	dump::~dump() {
+		if (CrashDumpFile) {
+			fflush(CrashDumpFile);
+		}
+	}
+
+	const dump &operator<<(const dump &stream, const char *str) {
+		if (!CrashDumpFile) return stream;
+
+		fwrite(str, 1, strlen(str), CrashDumpFile);
+		return stream;
+	}
+
+	const dump &operator<<(const dump &stream, int num) {
+		if (!CrashDumpFile) return stream;
+
+		if (num < 0) {
+			_writeChar('-');
+			num = -num;
+		}
+		int upper = 1, prev = num / 10;
+		while (prev >= upper) {
+			upper *= 10;
+		}
+		while (upper > 0) {
+			int digit = (num / upper);
+			_writeChar('0' + digit);
+			num -= digit * upper;
+			upper /= 10;
+		}
+		return stream;
+	}
+
+	void Handler(int signum) {
+		const char* name = 0;
+		switch (signum) {
+		case SIGABRT: name = "SIGABRT"; break;
+		case SIGSEGV: name = "SIGSEGV"; break;
+		case SIGILL: name = "SIGILL"; break;
+		case SIGFPE: name = "SIGFPE"; break;
+#ifndef Q_OS_WIN
+		case SIGBUS: name = "SIGBUS"; break;
+		case SIGSYS: name = "SIGSYS"; break;
+#endif
+		}
+
+		if (name) {
+			dump() << "Caught signal " << signum << " (" << name << ")\n";
+		} else {
+			dump() << "Caught signal " << signum << "\n";
+		}
+		dump() << "Platform: ";
+		switch (cPlatform()) {
+		case dbipWindows: dump() << "win"; break;
+		case dbipMac: dump() << "mac"; break;
+		case dbipMacOld: dump() << "macold"; break;
+		case dbipLinux64: dump() << "linux64"; break;
+		case dbipLinux32: dump() << "linux32"; break;
+		}
+		dump() << "\n\nBacktrace:\n";
+		psWriteStackTrace(CrashDumpFileNo);
+	}
+
+	Status start() {
+		CrashDumpPath = (cWorkingDir() + qsl("tdata/working")).toUtf8();
+		if (FILE *f = fopen(CrashDumpPath.constData(), "rb")) {
+			QByteArray lastdump;
+			char buffer[64 * 1024] = { 0 };
+			int32 read = 0;
+			while ((read = fread(buffer, 1, 64 * 1024, f)) > 0) {
+				lastdump.append(buffer, read);
+			}
+			fclose(f);
+
+			Global::SetLastCrashDump(lastdump);
+
+			LOG(("Opened '%1' for reading, the previous Telegram Desktop launch was not finished properly :( Crash log size: %2").arg(QString::fromUtf8(CrashDumpPath)).arg(lastdump.size()));
+
+			return LastCrashed;
+		}
+		return restart();
+	}
+
+	Status restart() {
+		CrashDumpFile = fopen(CrashDumpPath.constData(), "wb");
+		if (CrashDumpFile) {
+			CrashDumpFileNo = fileno(CrashDumpFile);
+
+			signal(SIGABRT, SignalHandlers::Handler);
+			signal(SIGSEGV, SignalHandlers::Handler);
+			signal(SIGILL, SignalHandlers::Handler);
+			signal(SIGFPE, SignalHandlers::Handler);
+#ifndef Q_OS_WIN
+			signal(SIGBUS, SignalHandlers::Handler);
+			signal(SIGSYS, SignalHandlers::Handler);
+#endif
+			return Started;
+		}
+
+		LOG(("Could not open '%1' for writing!").arg(QString::fromUtf8(CrashDumpPath)));
+
+		return CantOpen;
+	}
+
+	void finish() {
+		if (CrashDumpFile) {
+			fclose(CrashDumpFile);
+			unlink(CrashDumpPath.constData());
+		}
+	}
+
+}
diff --git a/Telegram/SourceFiles/logs.h b/Telegram/SourceFiles/logs.h
index bbfbc46ab..d706ba289 100644
--- a/Telegram/SourceFiles/logs.h
+++ b/Telegram/SourceFiles/logs.h
@@ -85,3 +85,22 @@ namespace Logs {
 
 #define MTP_LOG(dc, msg) { if (cDebug() || !Logs::started()) Logs::writeMtp(dc, QString msg); }
 //usage MTP_LOG(dc, ("log: %1 %2").arg(1).arg(2))
+
+namespace SignalHandlers {
+
+	struct dump {
+		~dump();
+	};
+	const dump &operator<<(const dump &stream, const char *str);
+	const dump &operator<<(const dump &stream, int num);
+
+	enum Status {
+		CantOpen,
+		LastCrashed,
+		Started
+	};
+	Status start();
+	Status restart(); // can be only CantOpen or Started
+	void finish();
+
+}
diff --git a/Telegram/SourceFiles/main.cpp b/Telegram/SourceFiles/main.cpp
index dde5bfaa6..e98700fda 100644
--- a/Telegram/SourceFiles/main.cpp
+++ b/Telegram/SourceFiles/main.cpp
@@ -67,5 +67,6 @@ int main(int argc, char *argv[]) {
 		psExecTelegram();
 	}
 
+	SignalHandlers::finish();
 	return result;
 }
diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp
index 847cb761f..3aa0aaef0 100644
--- a/Telegram/SourceFiles/pspecific_wnd.cpp
+++ b/Telegram/SourceFiles/pspecific_wnd.cpp
@@ -2368,6 +2368,88 @@ typedef BOOL (FAR STDAPICALLTYPE *t_miniDumpWriteDump)(
 );
 t_miniDumpWriteDump miniDumpWriteDump = 0;
 
+//// SymCleanup()
+//typedef BOOL(__stdcall *tSC)(IN HANDLE hProcess);
+//tSC pSC;
+//
+// SymFunctionTableAccess64()
+typedef PVOID (FAR STDAPICALLTYPE *t_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
+t_SymFunctionTableAccess64 symFunctionTableAccess64 = 0;
+
+//// SymGetLineFromAddr64()
+//typedef BOOL(__stdcall *tSGLFA)(IN HANDLE hProcess, IN DWORD64 dwAddr,
+//	OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line);
+//tSGLFA pSGLFA;
+//
+// SymGetModuleBase64()
+typedef DWORD64 (FAR STDAPICALLTYPE *t_SymGetModuleBase64)(IN HANDLE hProcess, IN DWORD64 dwAddr);
+t_SymGetModuleBase64 symGetModuleBase64 = 0;
+
+//// SymGetModuleInfo64()
+//typedef BOOL(__stdcall *tSGMI)(IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo);
+//tSGMI pSGMI;
+
+//  // SymGetModuleInfo64()
+//  typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );
+//  tSGMI_V3 pSGMI_V3;
+
+//// SymGetOptions()
+//typedef DWORD(__stdcall *tSGO)(VOID);
+//tSGO pSGO;
+//
+//// SymGetSymFromAddr64()
+//typedef BOOL(__stdcall *tSGSFA)(IN HANDLE hProcess, IN DWORD64 dwAddr,
+//	OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol);
+//tSGSFA pSGSFA;
+//
+//// SymInitialize()
+//typedef BOOL(__stdcall *tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
+//tSI pSI;
+//
+//// SymLoadModule64()
+//typedef DWORD64(__stdcall *tSLM)(IN HANDLE hProcess, IN HANDLE hFile,
+//	IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll);
+//tSLM pSLM;
+//
+//// SymSetOptions()
+//typedef DWORD(__stdcall *tSSO)(IN DWORD SymOptions);
+//tSSO pSSO;
+
+typedef BOOL (FAR STDAPICALLTYPE *t_StackWalk64)(
+	_In_ DWORD MachineType,
+	_In_ HANDLE hProcess,
+	_In_ HANDLE hThread,
+	_Inout_ LPSTACKFRAME64 StackFrame,
+	_Inout_ PVOID ContextRecord,
+	_In_opt_ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+	_In_opt_ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+	_In_opt_ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+	_In_opt_ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
+);
+t_StackWalk64 stackWalk64 = 0;
+
+//// UnDecorateSymbolName()
+//typedef DWORD(__stdcall WINAPI *tUDSN)(PCSTR DecoratedName, PSTR UnDecoratedName,
+//	DWORD UndecoratedLength, DWORD Flags);
+//tUDSN pUDSN;
+//
+//typedef BOOL(__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
+//tSGSP pSGSP;
+
+BOOL __stdcall ReadProcessMemoryRoutine64(
+	_In_ HANDLE hProcess,
+	_In_ DWORD64 qwBaseAddress,
+	_Out_writes_bytes_(nSize) PVOID lpBuffer,
+	_In_ DWORD nSize,
+	_Out_ LPDWORD lpNumberOfBytesRead
+	) {
+	SIZE_T st;
+	BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st);
+	*lpNumberOfBytesRead = (DWORD)st;
+	//printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
+	return bRet;
+}
+
 HANDLE _generateDumpFileAtPath(const WCHAR *path) {
 	static const int maxFileLen = MAX_PATH * 10;
 
@@ -2381,7 +2463,7 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) {
 		}
 	}
 
-    WCHAR szFileName[maxFileLen];
+	WCHAR szFileName[maxFileLen];
 	WCHAR szExeName[maxFileLen];
 
 	wcscpy_s(szExeName, _exeName);
@@ -2410,14 +2492,94 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) {
     return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
 }
 
+bool LoadDbgHelp() {
+	if (miniDumpWriteDump) return true;
+
+	HMODULE hDll = 0;
+
+	WCHAR szTemp[4096];
+	if (GetModuleFileName(NULL, szTemp, 4096) > 0) {
+		wcscat(szTemp, L".local");
+		if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) {
+			// ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
+			if (GetEnvironmentVariable(L"ProgramFiles", szTemp, 4096) > 0) {
+				wcscat(szTemp, L"\\Debugging Tools for Windows\\dbghelp.dll");
+				// now check if the file exists:
+				if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) {
+					hDll = LoadLibrary(szTemp);
+				}
+			}
+			// Still not found? Then try to load the 64-Bit version:
+			if (!hDll && (GetEnvironmentVariable(L"ProgramFiles", szTemp, 4096) > 0)) {
+				wcscat(szTemp, L"\\Debugging Tools for Windows 64-Bit\\dbghelp.dll");
+				if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) {
+					hDll = LoadLibrary(szTemp);
+				}
+			}
+		}
+	}
+	if (!hDll) {
+		hDll = LoadLibrary(L"DBGHELP.DLL");
+	}
+
+	if (!hDll) return false;
+
+	miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump");
+
+	//pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize");
+	//pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup");
+
+	stackWalk64 = (t_StackWalk64)GetProcAddress(hDll, "StackWalk64");
+	//pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions");
+	//pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions");
+
+	symFunctionTableAccess64 = (t_SymFunctionTableAccess64)GetProcAddress(hDll, "SymFunctionTableAccess64");
+	//pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64");
+	symGetModuleBase64 = (t_SymGetModuleBase64)GetProcAddress(hDll, "SymGetModuleBase64");
+	//pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64");
+	////pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
+	//pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64");
+	//pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName");
+	//pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64");
+	//pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath");
+
+	if (!miniDumpWriteDump ||
+		!stackWalk64) {
+		miniDumpWriteDump = 0;
+		return false;
+	}
+
+	//// SymInitialize
+	//if (szSymPath != NULL)
+	//	m_szSymPath = _strdup(szSymPath);
+	//if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
+	//	this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
+
+	//DWORD symOptions = this->pSGO();  // SymGetOptions
+	//symOptions |= SYMOPT_LOAD_LINES;
+	//symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
+	////symOptions |= SYMOPT_NO_PROMPTS;
+	//// SymSetOptions
+	//symOptions = this->pSSO(symOptions);
+
+	//char buf[StackWalker::STACKWALK_MAX_NAMELEN] = { 0 };
+	//if (this->pSGSP != NULL)
+	//{
+	//	if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
+	//		this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
+	//}
+	//char szUserName[1024] = { 0 };
+	//DWORD dwSize = 1024;
+	//GetUserNameA(szUserName, &dwSize);
+	//this->m_parent->OnSymInit(buf, symOptions, szUserName);
+
+	return true;
+}
+
 void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) {
 	static const int maxFileLen = MAX_PATH * 10;
 
-	HMODULE hDll = LoadLibrary(L"DBGHELP.DLL");
-	if (!hDll) return;
-
-	miniDumpWriteDump = (t_miniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump");
-	if (!miniDumpWriteDump) return;
+	if (!LoadDbgHelp()) return;
 
 	HANDLE hDumpFile = 0;
 
@@ -2465,6 +2627,150 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_op
 	return 0;
 }
 
+// stack walking code taken from StackWalker
+static const int StackEntryMaxNameLength = 1024;
+struct StackEntry {
+	DWORD64 offset;  // if 0, we have no valid entry
+	CHAR name[StackEntryMaxNameLength];
+	CHAR undName[StackEntryMaxNameLength];
+	CHAR undFullName[StackEntryMaxNameLength];
+	DWORD64 offsetFromSmybol;
+	DWORD offsetFromLine;
+	DWORD lineNumber;
+	CHAR lineFileName[StackEntryMaxNameLength];
+	DWORD symType;
+	LPCSTR symTypeString;
+	CHAR moduleName[StackEntryMaxNameLength];
+	DWORD64 baseOfImage;
+	CHAR loadedImageName[StackEntryMaxNameLength];
+};
+
+enum StackEntryType {
+	StackEntryFirst,
+	StackEntryNext,
+	StackEntryLast,
+};
+
+struct IMAGEHLP_MODULE64_V2 {
+	DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)
+	DWORD64  BaseOfImage;            // base load address of module
+	DWORD    ImageSize;              // virtual size of the loaded module
+	DWORD    TimeDateStamp;          // date/time stamp from pe header
+	DWORD    CheckSum;               // checksum from the pe header
+	DWORD    NumSyms;                // number of symbols in the symbol table
+	SYM_TYPE SymType;                // type of symbols loaded
+	CHAR     ModuleName[32];         // module name
+	CHAR     ImageName[256];         // image name
+	CHAR     LoadedImageName[256];   // symbol file name
+};
+
+char ImageHlpSymbol64[sizeof(IMAGEHLP_SYMBOL64) + StackEntryMaxNameLength];
+
+void psWriteStackTrace(int n) {
+	if (!LoadDbgHelp()) return;
+
+	HANDLE hThread = GetCurrentThread(), hProcess = GetCurrentProcess();
+	const CONTEXT *context = NULL;
+	LPVOID pUserData = NULL;
+
+	CONTEXT c;
+	StackEntry csEntry;
+	IMAGEHLP_SYMBOL64 *pSym = NULL;
+	IMAGEHLP_MODULE64_V2 Module;
+	IMAGEHLP_LINE64 Line;
+	int frameNum;
+
+	if (!LoadDbgHelp()) {
+		SignalHandlers::dump() << "ERROR: Could not load dbghelp.dll!\n";
+		return;
+	}
+
+	memset(&c, 0, sizeof(CONTEXT));
+	c.ContextFlags = CONTEXT_FULL;
+	RtlCaptureContext(&c);
+
+	// init STACKFRAME for first call
+	STACKFRAME64 s; // in/out stackframe
+	memset(&s, 0, sizeof(s));
+	DWORD imageType;
+#ifdef _M_IX86
+	// normally, call ImageNtHeader() and use machine info from PE header
+	imageType = IMAGE_FILE_MACHINE_I386;
+	s.AddrPC.Offset = c.Eip;
+	s.AddrPC.Mode = AddrModeFlat;
+	s.AddrFrame.Offset = c.Ebp;
+	s.AddrFrame.Mode = AddrModeFlat;
+	s.AddrStack.Offset = c.Esp;
+	s.AddrStack.Mode = AddrModeFlat;
+#elif _M_X64
+	imageType = IMAGE_FILE_MACHINE_AMD64;
+	s.AddrPC.Offset = c.Rip;
+	s.AddrPC.Mode = AddrModeFlat;
+	s.AddrFrame.Offset = c.Rsp;
+	s.AddrFrame.Mode = AddrModeFlat;
+	s.AddrStack.Offset = c.Rsp;
+	s.AddrStack.Mode = AddrModeFlat;
+#elif _M_IA64
+	imageType = IMAGE_FILE_MACHINE_IA64;
+	s.AddrPC.Offset = c.StIIP;
+	s.AddrPC.Mode = AddrModeFlat;
+	s.AddrFrame.Offset = c.IntSp;
+	s.AddrFrame.Mode = AddrModeFlat;
+	s.AddrBStore.Offset = c.RsBSP;
+	s.AddrBStore.Mode = AddrModeFlat;
+	s.AddrStack.Offset = c.IntSp;
+	s.AddrStack.Mode = AddrModeFlat;
+#else
+#error "Platform not supported!"
+#endif
+
+	pSym = (IMAGEHLP_SYMBOL64 *)ImageHlpSymbol64;
+	memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + StackEntryMaxNameLength);
+	pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+	pSym->MaxNameLength = StackEntryMaxNameLength;
+
+	memset(&Line, 0, sizeof(Line));
+	Line.SizeOfStruct = sizeof(Line);
+
+	memset(&Module, 0, sizeof(Module));
+	Module.SizeOfStruct = sizeof(Module);
+
+	for (frameNum = 0; ; ++frameNum) {
+		// get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
+		// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
+		// assume that either you are done, or that the stack is so hosed that the next
+		// deeper frame could not be found.
+		// CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
+		if (!stackWalk64(imageType, hProcess, hThread, &s, &c, ReadProcessMemoryRoutine64, symFunctionTableAccess64, symGetModuleBase64, NULL)) {
+			SignalHandlers::dump() << "ERROR: Call to StackWalk64() failed!\n";
+			return;
+		}
+
+		csEntry.offset = s.AddrPC.Offset;
+		csEntry.name[0] = 0;
+		csEntry.undName[0] = 0;
+		csEntry.undFullName[0] = 0;
+		csEntry.offsetFromSmybol = 0;
+		csEntry.offsetFromLine = 0;
+		csEntry.lineFileName[0] = 0;
+		csEntry.lineNumber = 0;
+		csEntry.loadedImageName[0] = 0;
+		csEntry.moduleName[0] = 0;
+		if (s.AddrPC.Offset == s.AddrReturn.Offset) {
+			SignalHandlers::dump() << s.AddrPC.Offset << "\n";
+			SignalHandlers::dump() << "ERROR: StackWalk64() endless callstack!";
+			return;
+		}
+		if (s.AddrPC.Offset != 0) { // we seem to have a valid PC
+			SignalHandlers::dump() << s.AddrPC.Offset << "\n";
+		}
+
+		if (s.AddrReturn.Offset == 0) {
+			break;
+		}
+	}
+}
+
 class StringReferenceWrapper {
 public:
 
diff --git a/Telegram/SourceFiles/pspecific_wnd.h b/Telegram/SourceFiles/pspecific_wnd.h
index b5f09d427..cbda8dc02 100644
--- a/Telegram/SourceFiles/pspecific_wnd.h
+++ b/Telegram/SourceFiles/pspecific_wnd.h
@@ -117,6 +117,8 @@ extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter;
 LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers);
 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
 
+void psWriteStackTrace(int n);
+
 void psDeleteDir(const QString &dir);
 
 void psUserActionDone();
diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h
index 44098d9e1..8f285ba20 100644
--- a/Telegram/SourceFiles/stdafx.h
+++ b/Telegram/SourceFiles/stdafx.h
@@ -22,6 +22,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
 #define PSAPI_VERSION 1 // fix WinXP
 //#define Q_NO_TEMPLATE_FRIENDS // fix some compiler difference issues
 
+#include <signal.h>
+
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
 #include <openssl/pem.h>
diff --git a/Telegram/SourceFiles/types.cpp b/Telegram/SourceFiles/types.cpp
index 6835e4956..7a1bdd170 100644
--- a/Telegram/SourceFiles/types.cpp
+++ b/Telegram/SourceFiles/types.cpp
@@ -22,8 +22,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
 
 #include "application.h"
 
-#include <signal.h>
-
 uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
 
 #ifdef Q_OS_WIN
@@ -309,47 +307,6 @@ namespace ThirdParty {
 
 }
 
-namespace {
-	FILE *_crashDump = 0;
-	int _crashDumpNo = 0;
-}
-
-void _signalHandler(int signum) {
-	const char* name = 0;
-	switch (signum) {
-	case SIGABRT: name = "SIGABRT"; break;
-	case SIGSEGV: name = "SIGSEGV"; break;
-	case SIGILL: name = "SIGILL"; break;
-	case SIGFPE: name = "SIGFPE"; break;
-#ifndef Q_OS_WIN
-	case SIGBUS: name = "SIGBUS"; break;
-	case SIGSYS: name = "SIGSYS"; break;
-#endif
-	}
-	LOG(("Caught signal %1").arg(name));
-	if (name)
-		fprintf(stdout, "Caught signal %d (%s)\n", signum, name);
-	else
-		fprintf(stdout, "Caught signal %d\n", signum);
-
-
-	//printStackTrace();
-}
-
-void installSignalHandlers() {
-	_crashDump = fopen((cWorkingDir() + qsl("tdata/working")).toUtf8().constData(), "wb");
-	if (_crashDump) _crashDumpNo = fileno(_crashDump);
-
-	signal(SIGABRT, _signalHandler);
-	signal(SIGSEGV, _signalHandler);
-	signal(SIGILL, _signalHandler);
-	signal(SIGFPE, _signalHandler);
-#ifndef Q_OS_WIN
-	signal(SIGBUS, _signalHandler);
-	signal(SIGSYS, _signalHandler);
-#endif
-}
-
 bool checkms() {
 	int64 unixms = (myunixtime() - _timeStart) * 1000LL + _msAddToUnixtime;
 	int64 ms = int64(getms(true));
diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h
index 50ddd51e9..d7043d70b 100644
--- a/Telegram/SourceFiles/types.h
+++ b/Telegram/SourceFiles/types.h
@@ -143,8 +143,6 @@ inline void mylocaltime(struct tm * _Tm, const time_t * _Time) {
 #endif
 }
 
-void installSignalHandlers();
-
 namespace ThirdParty {
 
 	void start();