diff options
| -rw-r--r-- | .gitignore | 15 | ||||
| -rw-r--r-- | LICENSE | 15 | ||||
| -rw-r--r-- | Makefile | 23 | ||||
| -rw-r--r-- | config.mk | 8 | ||||
| -rw-r--r-- | stackdump-on-crash.c | 117 |
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 @@ -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 +} |
