#define ensure(cond) \
dbc_ensure(cond, #cond, __FILE__, __LINE__)
-void dbc_init(void (*)(FILE*));
+void dbc_init(char* path, void (*dumpfn)(FILE*));
void dbc_require(bool success, char* text, char* file, int line);
void dbc_ensure(bool success, char* text, char* file, int line);
+void dbc_wdtkick(void);
static bool buf_selvalid(Buf* buf) {
(void)buf;
- return true;
+ return (buf->selection.beg <= buf->selection.end);
+// return true;
}
static bool buf_valid(Buf* buf) {
for (; isword(buf_getrat(buf, sel.beg-1)); sel.beg--);
for (; isword(buf_getrat(buf, sel.end)); sel.end++);
buf->selection = sel;
+ ensure(buf_selvalid(buf));
}
void buf_selall(Buf* buf) {
buf->selection = (Sel){ .beg = 0, .end = buf_end(buf) };
+ ensure(buf_selvalid(buf));
}
static bool selquote(Buf* buf, Rune c) {
else
buf_selword(buf, risbigword);
buf_getcol(buf);
+ ensure(buf_selvalid(buf));
}
size_t buf_byrune(Buf* buf, size_t pos, int count) {
line--, curr = next;
}
buf->selection.beg = buf->selection.end = curr;
+ ensure(buf_selvalid(buf));
}
void buf_getln(Buf* buf, size_t* begln, size_t* endln) {
i += width;
}
buf->selection = sel;
+ ensure(buf_selvalid(buf));
}
size_t buf_selbeg(Buf* buf) {
buf->selection.beg = buf->selection.end;
else
buf->selection.end = buf->selection.beg;
+ ensure(buf_selvalid(buf));
}
bool buf_insel(Buf* buf, size_t off) {
#include <dbc.h>
#include <stdio.h>
+#include <signal.h>
+static char ErrMsg[8192];
+static char* DumpPath = NULL;
static void (*DumpFn)(FILE*) = NULL;
static void dump_and_abort(char* msg) {
- FILE* f = fopen("/tmp/tide.dump", "w");
- fprintf(f, "%s\n", msg);
+ FILE* f = (DumpPath ? fopen(DumpPath, "w") : stderr);
+ fprintf(f, "%s\n\n", msg);
if (DumpFn) DumpFn(f);
fclose(f);
abort();
}
-void dbc_init(void (*dumpfn)(FILE*)) {
-#ifndef NDEBUG
+static void handle_signal(int sig) {
+ if (SIGBUS == sig) {
+ dump_and_abort("SIGBUS - Access to an undefined portion of a memory object");
+ } else if (SIGFPE == sig) {
+ dump_and_abort("SIGFPE - Erroneous arithmetic operation");
+ } else if (SIGILL == sig) {
+ dump_and_abort("SIGILL - Illegal instruction");
+ } else if (SIGSEGV == sig) {
+ dump_and_abort("SIGSEGV - Invalid memory reference");
+ } else if (SIGALRM == sig) {
+ dump_and_abort("SIGALRM - Watchdog timer expired");
+ }
+}
+
+void dbc_init(char* path, void (*dumpfn)(FILE*)) {
+ DumpPath = path;
DumpFn = dumpfn;
-#endif
+ signal(SIGBUS, handle_signal);
+ signal(SIGFPE, handle_signal);
+ signal(SIGILL, handle_signal);
+ signal(SIGSEGV, handle_signal);
}
void dbc_require(bool success, char* text, char* file, int line) {
-#ifndef NDEBUG
- char buf[8192];
if (!success) {
- snprintf(buf, sizeof(buf), "%s:%d: pre-condition failed (%s)", file, line, text);
- dump_and_abort(buf);
+ snprintf(ErrMsg, sizeof(ErrMsg), "%s:%d: pre-condition failed (%s)", file, line, text);
+ dump_and_abort(ErrMsg);
}
-#endif
}
void dbc_ensure(bool success, char* text, char* file, int line) {
-#ifndef NDEBUG
- char buf[8192];
if (!success) {
- snprintf(buf, sizeof(buf), "%s:%d: post-condition failed (%s)", file, line, text);
- dump_and_abort(buf);
+ snprintf(ErrMsg, sizeof(ErrMsg), "%s:%d: post-condition failed (%s)", file, line, text);
+ dump_and_abort(ErrMsg);
}
-#endif
+}
+
+void dbc_wdtkick(void) {
+ alarm(0); /* Cancel previous alarm */
+ signal(SIGALRM, handle_signal);
+ alarm(1); /* Start new alarm */
}
#define PRESSED(mods, btn) \
((mods & (1 << (btn + 7))) == (1 << (btn + 7)))
+/* Crash Dump Handling
+ ******************************************************************************/
+void dumpdata(FILE* f) {
+ fprintf(f, "Focused:\t%d\n", Focused);
+ fprintf(f, "Divider:\t%d\n", Divider);
+ fprintf(f, "FontSel:\t%d\n", FontSel);
+ fprintf(f, "SyncMouse:\t%d\n", SyncMouse);
+ fprintf(f, "SearchDir:\t%d\n", SearchDir);
+ fprintf(f, "SearchTerm:\t'%s'\n", SearchTerm);
+ for (int i = 0; i < NREGIONS; i++) {
+ fprintf(f, "Region[%d]:\n", i);
+ fprintf(f, "\t.sync_flags:\t%d\n", Regions[i].sync_flags);
+ fprintf(f, "\t.index:\t\t%zu\n", Regions[i].index);
+ fprintf(f, "\t.width:\t\t%zu\n", Regions[i].width);
+ fprintf(f, "\t.nvisible:\t%zu\n", Regions[i].nvisible);
+ fprintf(f, "\t.nrows:\t\t%zu\n", Regions[i].nrows);
+ fprintf(f, "\t.rows:\t\t%p\n", (void*)Regions[i].rows);
+ fprintf(f, "\t.buffer:\n");
+ fprintf(f, "\t\t.status:\t%d\n", Regions[i].buffer.status);
+ fprintf(f, "\t\t.modtime:\t%llu\n", Regions[i].buffer.modtime);
+ fprintf(f, "\t\t.bufsize:\t%zu\n", Regions[i].buffer.bufsize);
+ fprintf(f, "\t\t.bufstart:\t%p\n", (void*)Regions[i].buffer.bufstart);
+ fprintf(f, "\t\t.bufend:\t%p\n", (void*)Regions[i].buffer.bufend);
+ fprintf(f, "\t\t.gapstart:\t%p\n", (void*)Regions[i].buffer.gapstart);
+ fprintf(f, "\t\t.gapend:\t%p\n", (void*)Regions[i].buffer.gapend);
+ fprintf(f, "\t\t.undo:\t\t%p\n", (void*)Regions[i].buffer.undo);
+ fprintf(f, "\t\t.redo:\t\t%p\n", (void*)Regions[i].buffer.redo);
+ fprintf(f, "\t\t.save:\t\t%p\n", (void*)Regions[i].buffer.save);
+ fprintf(f, "\t\t.transid:\t%d\n", Regions[i].buffer.transid);
+ fprintf(f, "\t\t.selbeg:\t%zu\n", Regions[i].buffer.selection.beg);
+ fprintf(f, "\t\t.selend:\t%zu\n", Regions[i].buffer.selection.end);
+ fprintf(f, "\t\t.selcol:\t%zu\n", Regions[i].buffer.selection.col);
+ }
+}
+
/* X11 Window Code
******************************************************************************/
static void font_load(char* name) {
int maxcount = 1000 / Timeout;
int count = 0;
while (X.running) {
+ dbc_wdtkick();
bool ready = job_poll(Timeout);
count += (ready ? -count : 1);
if (count < maxcount)
view_resize(win_view(TAGS), 640, 1);
buf_logclear(win_buf(TAGS));
win_prop_set("TIDE", "", "tide");
+ dbc_init(NULL, dumpdata);
/* if we still have args left we're going to open it in this instance */
if (*argv) {