diff options
-rw-r--r-- | .gitignore | 10 | ||||
-rw-r--r-- | LICENSE | 15 | ||||
-rw-r--r-- | Makefile | 63 | ||||
-rw-r--r-- | config.mk | 6 | ||||
-rw-r--r-- | internal.h | 25 | ||||
-rw-r--r-- | linux.mk | 5 | ||||
-rw-r--r-- | macos.mk | 5 | ||||
-rw-r--r-- | print_backtrace.c | 75 | ||||
-rw-r--r-- | save_backtrace.c | 61 |
9 files changed, 265 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..983233b --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*\#* +*~ +*.o +*.a +*.lo +*.so +*.so.* +*.su +*.dll +*.dylib @@ -0,0 +1,15 @@ +ISC License + +© 2019 Mattias Andrée <maandree@kth.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..924776d --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OS = linux +# linux = Linux +# macos = Mac OS +include $(OS).mk + +LIB_MAJOR = 1 +LIB_MINOR = 0 +LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) + + +HDR =\ + internal.h + +OBJ =\ + print_backtrace.o\ + save_backtrace.o + +LOBJ = $(OBJ:.o=.lo) + + +all: liberror-backtrace.a liberror-backtrace.$(LIBEXT) +$(OBJ): $(@:.o=.c) $(HDR) +$(LOBJ): $(@:.lo=.c) $(HDR) + +liberror-backtrace.a: $(OBJ) + -rm -f -- $@ + $(AR) rc $@ $(OBJ) + $(AR) s $@ + +liberror-backtrace.$(LIBEXT): $(LOBJ) + $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS) + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.c.lo: + $(CC) -c -o $@ $< -fPIC $(CFLAGS) $(CPPFLAGS) + +install: liberror-backtrace.a liberror-backtrace.$(LIBEXT) + mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" + mkdir -p -- "$(DESTDIR)$(PREFIX)/licenses/liberror-backtrace" + cp -- liberror-backtrace.a "$(DESTDIR)$(PREFIX)/lib" + cp -- liberror-backtrace.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/liberror-backtrace.$(LIBMINOREXT)" + ln -sf -- liberror-backtrace.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/liberror-backtrace.$(LIBMAJOREXT)" + ln -sf -- liberror-backtrace.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/liberror-backtrace.$(LIBEXT)" + cp -- LICENSE "$(DESTDIR)$(PREFIX)/licenses/liberror-backtrace" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/liberror-backtrace."* + -rm -rf -- "$(DESTDIR)$(PREFIX)/licenses/liberror-backtrace" + +clean: + -rm -f -- *.o *.lo *.a *.so *.so.* *.su *.test + +.SUFFIXES: +.SUFFIXES: .c .o .lo .a + +.PHONY: all install uninstall clean diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..fa0eba8 --- /dev/null +++ b/config.mk @@ -0,0 +1,6 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 +CFLAGS = -std=c11 -Wall -pedantic +LDFLAGS = -s -lunwind -ldw diff --git a/internal.h b/internal.h new file mode 100644 index 0000000..e2d1652 --- /dev/null +++ b/internal.h @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#include <alloca.h> +#include <errno.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +struct liberror_error { + struct liberror_backtrace *backtrace; +}; + + +struct liberror_backtrace { + size_t refcount; + size_t n; + uintptr_t rips[]; +}; + + +void liberror_print_backtrace(struct liberror_error *, FILE *, const char *); +int liberror_save_backtrace_(struct liberror_error *); diff --git a/linux.mk b/linux.mk new file mode 100644 index 0000000..c9f74a0 --- /dev/null +++ b/linux.mk @@ -0,0 +1,5 @@ +LIBEXT = so +LIBFLAGS = -shared -Wl,-soname,libkeccak.$(LIBEXT).$(LIB_MAJOR) + +LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR) +LIBMINOREXT = $(LIBEXT).$(LIB_VERSION) diff --git a/macos.mk b/macos.mk new file mode 100644 index 0000000..b475197 --- /dev/null +++ b/macos.mk @@ -0,0 +1,5 @@ +LIBEXT = dylib +LIBFLAGS = -dynamiclib + +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) diff --git a/print_backtrace.c b/print_backtrace.c new file mode 100644 index 0000000..d8a53e8 --- /dev/null +++ b/print_backtrace.c @@ -0,0 +1,75 @@ +/* See LICENSE file for copyright and license details. */ +#include "internal.h" + +#include <elfutils/libdwfl.h> + + +void +liberror_print_backtrace(struct liberror_error *error, FILE *fp, const char *indent) +{ + struct liberror_backtrace *backtrace; + int saved_errno = errno, full_paths, lineno; + char *debuginfo_path = NULL, *env; + 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; + size_t i; + + if (!error) + return; + + backtrace = error->backtrace; + if (!backtrace) + return; + + 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; + + env = getenv("LIBERROR_FULL_PATHS"); + full_paths = env && (*env == 'Y' || *env == 'y' || *env == '1'); + + dwfl = dwfl_begin(&callbacks); + + if (dwfl) { + if (dwfl_linux_proc_report(dwfl, getpid()) || + dwfl_report_end(dwfl, NULL, NULL)) { + dwfl_end(dwfl); + dwfl = NULL; + } + } + + for (i = 0; i < backtrace->n; i++) { + ip = (Dwarf_Addr)backtrace->rips[i]; + + 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(fp, "%s%s 0x%016"PRIxPTR": %s", + indent, !i ? "at" : "by", + (uintptr_t)ip, + funcname ? funcname : "???"); + if (line) + fprintf(fp, " (%s:%i)\n", filename, lineno); + else + fprintf(fp, "\n"); + } + + if (dwfl) + dwfl_end(dwfl); + errno = saved_errno; +} diff --git a/save_backtrace.c b/save_backtrace.c new file mode 100644 index 0000000..e366abf --- /dev/null +++ b/save_backtrace.c @@ -0,0 +1,61 @@ +/* See LICENSE file for copyright and license details. */ +#include "internal.h" + +#define UNW_LOCAL_ONLY +#include <libunwind.h> + + +struct partial { + uintptr_t rips[8]; + struct partial *next; +}; + + +int +liberror_save_backtrace(struct liberror_error *error) +{ + struct liberror_backtrace *backtrace = NULL; + unw_word_t rip; + unw_cursor_t cursor; + unw_context_t context; + size_t i = 0; + struct partial *current, head; + int saved_errno = errno; + int ret = -1; + + if (unw_getcontext(&context)) + goto out; + if (unw_init_local(&cursor, &context)) + goto out; + + current = &head; + + for (; unw_step(&cursor) > 0; i++) { + if (!(i & 7)) + current = current->next = alloca(sizeof(*current)); + if (unw_get_reg(&cursor, UNW_REG_IP, &rip)) + goto out; + current->rips[i & 7] = (uintptr_t)rip; + } + + backtrace = malloc(offsetof(struct liberror_backtrace, rips) + i * sizeof(*backtrace->rips)); + if (!backtrace) + goto out; + backtrace->refcount = 1; + + backtrace->n = i; + current = &head; + for (i = 0; i < backtrace->n; i++) { + if (!(i & 7)) + current = current->next; + backtrace->rips[i] = current->rips[i & 7]; + } + + ret = 0; +out: + if (error->backtrace && !--error->backtrace->refcount) + free(error->backtrace); + error->backtrace = backtrace; + errno = saved_errno; + return ret; +} |