aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore10
-rw-r--r--LICENSE15
-rw-r--r--Makefile63
-rw-r--r--config.mk6
-rw-r--r--internal.h25
-rw-r--r--linux.mk5
-rw-r--r--macos.mk5
-rw-r--r--print_backtrace.c75
-rw-r--r--save_backtrace.c61
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
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c437151
--- /dev/null
+++ b/LICENSE
@@ -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;
+}