From f7b4088919bed74397e55ce2eab7aad61df3c949 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Fri, 12 Apr 2019 21:12:21 +0200 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 10 ++++++++ LICENSE | 15 +++++++++++ Makefile | 63 ++++++++++++++++++++++++++++++++++++++++++++++ config.mk | 6 +++++ internal.h | 25 +++++++++++++++++++ linux.mk | 5 ++++ macos.mk | 5 ++++ print_backtrace.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ save_backtrace.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 265 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 config.mk create mode 100644 internal.h create mode 100644 linux.mk create mode 100644 macos.mk create mode 100644 print_backtrace.c create mode 100644 save_backtrace.c 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 + +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 +#include +#include +#include +#include +#include +#include +#include + + +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 + + +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 + + +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; +} -- cgit v1.2.3-70-g09d2