aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore15
-rw-r--r--LICENSE15
-rw-r--r--Makefile23
-rw-r--r--config.mk8
-rw-r--r--stackdump-on-crash.c117
5 files changed, 178 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3cbdeb1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*\#*
+*~
+*.o
+*.a
+*.lo
+*.su
+*.so
+*.so.*
+*.dll
+*.dylib
+*.gch
+*.gcov
+*.gcno
+*.gcda
+/stackdump-on-crash
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1634eae
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 2026 Mattias Andrée <m@maandree.se>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..390ad73
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+OBJ =\
+ stackdump-on-crash.o
+
+all: stackdump-on-crash
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+stackdump-on-crash: $(OBJ)
+ $(CC) -o $@ $(OBJ) $(LDFLAGS)
+
+clean:
+ -rm -f -- *.o *.su stackdump-on-crash
+
+.SUFFIXES:
+.SUFFIXES: .o .c
+
+.PHONY: all clean
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..af01644
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,8 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = c99
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
+CFLAGS = -g
+LDFLAGS = -lunwind -ldw
diff --git a/stackdump-on-crash.c b/stackdump-on-crash.c
new file mode 100644
index 0000000..70493ba
--- /dev/null
+++ b/stackdump-on-crash.c
@@ -0,0 +1,117 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UNW_LOCAL_ONLY
+#include <elfutils/libdwfl.h>
+#include <libunwind.h>
+
+
+static const int full_paths = 0;
+
+
+static void
+dump_stack(ucontext_t *ucontext)
+{
+ int saved_errno = errno, lineno;
+ unw_word_t rip;
+ unw_cursor_t cursor;
+ char *debuginfo_path = NULL;
+ Dwarf_Addr ip;
+ Dwfl_Callbacks callbacks;
+ Dwfl *dwfl = NULL;
+ Dwfl_Line *line = NULL;
+ Dwfl_Module *module = NULL;
+ const char *filename = NULL, *p;
+ const char *funcname = NULL;
+ int first = 1;
+
+ if (unw_init_local2(&cursor, ucontext, UNW_INIT_SIGNAL_FRAME))
+ goto out;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+
+ callbacks.find_elf = dwfl_linux_proc_find_elf;
+ callbacks.find_debuginfo = dwfl_standard_find_debuginfo;
+ callbacks.debuginfo_path = &debuginfo_path;
+
+
+ dwfl = dwfl_begin(&callbacks);
+
+ if (dwfl) {
+ if (dwfl_linux_proc_report(dwfl, getpid()) ||
+ dwfl_report_end(dwfl, NULL, NULL)) {
+ dwfl_end(dwfl);
+ dwfl = NULL;
+ }
+ }
+
+ do {
+ if (unw_get_reg(&cursor, UNW_REG_IP, &rip))
+ break;
+ ip = (Dwarf_Addr)rip;
+
+ if (dwfl) {
+ module = dwfl_addrmodule(dwfl, ip);
+ funcname = module ? dwfl_module_addrname(module, ip) : NULL;
+ line = dwfl_getsrc(dwfl, ip);
+ if (line) {
+ filename = dwfl_lineinfo(line, &(Dwarf_Addr){0},
+ &lineno, NULL, NULL, NULL);
+ if (!full_paths && (p = strrchr(filename, '/')))
+ filename = &p[1];
+ }
+ }
+
+ fprintf(stderr, "%s 0x%016"PRIxPTR": %s",
+ first ? "crashed at" : " by",
+ (uintptr_t)ip,
+ funcname ? funcname : "???");
+ first = 0;
+ if (line)
+ fprintf(stderr, " (%s:%i)\n", filename, lineno);
+ else
+ fprintf(stderr, "\n");
+
+ } while (unw_step(&cursor) > 0);
+
+ if (dwfl)
+ dwfl_end(dwfl);
+out:
+ errno = saved_errno;
+}
+
+
+static void
+stack_dumper(int sig, siginfo_t *info, void *ucontext)
+{
+ (void) sig;
+ (void) info;
+ dump_stack(ucontext);
+}
+
+
+int
+main(void)
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = &stack_dumper;
+ sa.sa_flags = (int)(SA_RESETHAND | SA_SIGINFO);
+
+#if 1
+ {
+ static volatile int *null = NULL;
+ sigaction(SIGSEGV, &sa, NULL);
+ return *null;
+ }
+#else
+ sigaction(SIGABRT, &sa, NULL);
+ abort();
+ return 0;
+#endif
+}