summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-03-01 22:22:39 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-03-01 22:22:39 -0500
commitd94f61b5d52d3372c006aad67ccd133926666f18 (patch)
tree2b2df83684a183d56bdc50a095d98d91d0941979
parent12bb6e2cd377d3dfa2f7ec037c31463c3f9070d1 (diff)
crash handler for windows
-rw-r--r--base.h1
-rw-r--r--main.c104
-rw-r--r--make.bat4
3 files changed, 100 insertions, 9 deletions
diff --git a/base.h b/base.h
index 8994daf..4cbb1dc 100644
--- a/base.h
+++ b/base.h
@@ -12,6 +12,7 @@
#if _WIN32
#include <windows.h>
#include <shlobj.h>
+#include <dbghelp.h>
#define PATH_SEPARATOR '\\'
#define PATH_SEPARATOR_STR "\\"
// on windows, let the user use forwards slashes as well as backslashes
diff --git a/main.c b/main.c
index 6524b40..b96deaa 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,5 @@
// @TODO:
-// - "on crash, output backtrace to log" for Windows
+// - fix: after closing last tab in active node, there should be a new active node
// - Windows installation
// - test on BSD
@@ -23,6 +23,10 @@ no_warn_end
#endif
#if _WIN32
#include <shellapi.h>
+#pragma comment(lib, "dbghelp.lib")
+#pragma comment(lib, "ole32.lib")
+#pragma comment(lib, "opengl32.lib")
+#pragma comment(lib, "shell32.lib")
#endif
#define PCRE2_STATIC
#define PCRE2_CODE_UNIT_WIDTH 32
@@ -114,13 +118,18 @@ static void APIENTRY gl_message_callback(GLenum source, GLenum type, unsigned in
}
#endif
-#if __unix__
+#define CRASH_CRASH_MESSAGE "ted crashed while trying to handle a crash! yikes! ):"
+#define CRASH_MESSAGE "ted has crashed ): Please send %s/log.txt to pommicket""@gmail.com if you want this fixed.", ted->local_data_dir
+#define CRASH_STARTUP_MESSAGE "ted crashed when starting up ):"
+
static Ted *error_signal_handler_ted;
static bool signal_being_handled; // prevent infinite signal recursion
+#if __unix__
static void error_signal_handler(int signum, siginfo_t *info, void *context) {
(void)context;
if (signal_being_handled)
- die("ted crashed while trying to handle a crash! yikes! ):");
+ die(CRASH_CRASH_MESSAGE);
+ signal_being_handled = true;
Ted *ted = error_signal_handler_ted;
if (ted) {
FILE *log = ted->log;
@@ -147,12 +156,85 @@ static void error_signal_handler(int signum, siginfo_t *info, void *context) {
#endif
fclose(log);
}
- session_write(ted);
- die("ted has crashed ): Please send %s/log.txt to pommicket""@gmail.com if you want this fixed.", ted->local_data_dir);
+ die(CRASH_MESSAGE);
+ } else {
+ die(CRASH_STARTUP_MESSAGE);
+ }
+}
+#elif _WIN32
+static char const *windows_exception_to_str(DWORD exception_code) {
+ switch (exception_code) {
+ case EXCEPTION_ACCESS_VIOLATION: return "Access violation";
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array out of bounds";
+ case EXCEPTION_BREAKPOINT: return "Breakpoint";
+ case EXCEPTION_DATATYPE_MISALIGNMENT: return "Misaligned read or write";
+ case EXCEPTION_FLT_DENORMAL_OPERAND: return "Floating-point denormal operand";
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "Floating-point division by zero";
+ case EXCEPTION_FLT_INEXACT_RESULT: return "Floating-point inexact result";
+ case EXCEPTION_FLT_INVALID_OPERATION: return "Floating-point invalid operation";
+ case EXCEPTION_FLT_OVERFLOW: return "Floating-point overflow";
+ case EXCEPTION_FLT_STACK_CHECK: return "Floating-point stack over/underflow";
+ case EXCEPTION_FLT_UNDERFLOW: return "Floating-point underflow";
+ case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction";
+ case EXCEPTION_IN_PAGE_ERROR: return "Page not present";
+ case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer divide by zero";
+ case EXCEPTION_INT_OVERFLOW: return "Integer overflow";
+ case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition";
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Continue after non-continuable exception";
+ case EXCEPTION_PRIV_INSTRUCTION: return "Private instruction executed";
+ case EXCEPTION_SINGLE_STEP: return "Single step";
+ case EXCEPTION_STACK_OVERFLOW: return "Stack overflow";
+ }
+ return "Unknown exception";
+}
+
+
+static LONG WINAPI error_signal_handler(EXCEPTION_POINTERS *info) {
+ if (signal_being_handled)
+ die(CRASH_CRASH_MESSAGE);
+ signal_being_handled = true;
+ Ted *ted = error_signal_handler_ted;
+ if (ted) {
+ FILE *log = ted->log;
+ if (log) {
+ DWORD exception_code = info->ExceptionRecord->ExceptionCode;
+ fprintf(log, "Exception 0x%lx: %s.\n", (unsigned long)exception_code, windows_exception_to_str(exception_code));
+ fprintf(log, "Address: 0x%llx.\n", (unsigned long long)info->ExceptionRecord->ExceptionAddress);
+ fprintf(log, "Info0: 0x%llx.\n", (unsigned long long)info->ExceptionRecord->ExceptionInformation[0]);
+ fprintf(log, "Info1: 0x%llx.\n", (unsigned long long)info->ExceptionRecord->ExceptionInformation[1]);
+ fprintf(log, "Info2: 0x%llx.\n", (unsigned long long)info->ExceptionRecord->ExceptionInformation[2]);
+ #if _M_AMD64
+ CONTEXT *context = info->ContextRecord;
+ if (exception_code == EXCEPTION_STACK_OVERFLOW) {
+ // don't backtrace; just output current address
+ fprintf(log, "Instruction: 0x%llx\n", (unsigned long long)context->Rip);
+ } else {
+ fprintf(log, "Backtrace:\n");
+ HANDLE process = GetCurrentProcess(), thread = GetCurrentThread();
+ // backtrace
+ // this here was very helpful: https://gist.github.com/jvranish/4441299
+ if (SymInitialize(process, NULL, true)) {
+ STACKFRAME frame = {0};
+ frame.AddrPC.Offset = context->Rip;
+ frame.AddrStack.Offset = context->Rsp;
+ frame.AddrFrame.Offset = context->Rbp;
+ frame.AddrPC.Mode = frame.AddrStack.Mode = frame.AddrFrame.Mode = AddrModeFlat;
+ while (StackWalk(IMAGE_FILE_MACHINE_AMD64, process, thread,
+ &frame, context, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL)) {
+ fprintf(log, "0x%llx\n", (unsigned long long)frame.AddrPC.Offset);
+ }
+ SymCleanup(process);
+ }
+ }
+ #endif
+ fclose(log);
+ }
+ die(CRASH_MESSAGE);
} else {
- die("ted crashed when starting up ):");
+ die(CRASH_STARTUP_MESSAGE);
}
+ return EXCEPTION_EXECUTE_HANDLER;
}
#endif
@@ -242,6 +324,10 @@ int main(int argc, char **argv) {
sigaction(SIGILL, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
}
+#elif _WIN32
+ SetUnhandledExceptionFilter(error_signal_handler);
+#else
+ #error "Unrecognized operating system."
#endif
setlocale(LC_ALL, ""); // allow unicode
@@ -272,7 +358,8 @@ int main(int argc, char **argv) {
if (!ted) {
die("Not enough memory available to run ted.");
}
-
+
+ // make sure signal handler has access to ted.
error_signal_handler_ted = ted;
{ // get local data directory
@@ -297,6 +384,9 @@ int main(int argc, char **argv) {
strbuf_printf(ted->global_data_dir, "/usr/share/ted");
#endif
+ if (fs_path_type(ted->local_data_dir) == FS_NON_EXISTENT)
+ fs_mkdir(ted->local_data_dir);
+
}
FILE *log = NULL;
diff --git a/make.bat b/make.bat
index 80c7990..0a11e02 100644
--- a/make.bat
+++ b/make.bat
@@ -10,10 +10,10 @@ if not exist pcre2-32.lib (
popd
copy pcre2-10.36\Release\pcre2-32.lib
)
-SET C_FLAGS=/nologo /W4 /MD /wd4200 /wd4204 /wd4221 /wd4706 /wd4214 /D_CRT_SECURE_NO_WARNINGS /I pcre2-10.36 /I SDL2/include SDL2/lib/x64/SDL2main.lib SDL2/lib/x64/SDL2.lib opengl32.lib shell32.lib ole32.lib pcre2-32.lib
+SET C_FLAGS=/nologo /W4 /MD /wd4200 /wd4204 /wd4221 /wd4706 /wd4214 /D_CRT_SECURE_NO_WARNINGS /I pcre2-10.36 /I SDL2/include SDL2/lib/x64/SDL2main.lib SDL2/lib/x64/SDL2.lib pcre2-32.lib
rc /nologo ted.rc
if _%1 == _ (
- cl main.c ted.res /DDEBUG /DEBUG /Zi %C_FLAGS% /Fe:ted
+ cl main.c stb_truetype.c ted.res /DDEBUG /DEBUG /Zi %C_FLAGS% /Fe:ted
)
if _%1 == _release cl main.c ted.res /O2 %C_FLAGS% /Fe:ted
if _%1 == _release_with_debug_info cl main.c ted.res /DEBUG /Zi /O2 %C_FLAGS% /Fe:ted