--- /dev/null
+# $OpenBSD: Makefile,v 1.1 2021/06/09 19:37:43 mortimer Exp $
+
+.include <bsd.own.mk>
+
+USE_UNWIND=no
+.if ${COMPILER_VERSION} == "clang"
+USE_UNWIND=yes
+.endif
+
+LIB=execinfo
+SRCS=backtrace.c
+MAN= backtrace.3
+
+.if empty(CFLAGS:M-std=*)
+CFLAGS+= -std=gnu99
+.endif
+
+.if ${USE_UNWIND} == "yes"
+.PATH: ${SRCDIR} ${BSDSRCDIR}/gnu/llvm/libunwind/src
+.PATH: ${SRCDIR} ${BSDSRCDIR}/gnu/llvm/libcxx/src
+CXXFLAGS+= -I${BSDSRCDIR}/gnu/llvm/libunwind/include \
+ -I${BSDSRCDIR}/gnu/llvm/libcxx/include
+CFLAGS+= -I${BSDSRCDIR}/gnu/llvm/libunwind/include
+
+CPPFLAGS+= -D_LIBUNWIND_IS_NATIVE_ONLY
+CPPFLAGS+= -DLIBUNWIND_USE_WEAK_PTHREAD
+CPPFLAGS+= -DNDEBUG
+CXXFLAGS+= -nostdlib -nostdinc++ -funwind-tables \
+ -fno-exceptions -fno-rtti
+.if empty(CXXFLAGS:M-std=*)
+CXXFLAGS+= -std=c++11
+.endif
+
+SRCS+=unwind.c \
+ Unwind-EHABI.cpp \
+ Unwind-sjlj.c \
+ UnwindLevel1-gcc-ext.c \
+ UnwindLevel1.c \
+ UnwindRegistersRestore.S \
+ UnwindRegistersSave.S \
+ libunwind.cpp \
+ new.cpp
+
+.else # !${USE_UNWIND}
+SRCS+=builtin.c
+.endif
+
+VERSION_SCRIPT= ${.CURDIR}/Symbols.map
+
+includes:
+ cmp -s ${DESTDIR}/usr/include/execinfo.h ${.CURDIR}/execinfo.h || \
+ ${INSTALL} ${INSTALL_COPY} -m 444 -o $(BINOWN) -g $(BINGRP) \
+ ${.CURDIR}/execinfo.h ${DESTDIR}/usr/include/execinfo.h
+
+.include <bsd.lib.mk>
--- /dev/null
+{
+ global:
+ backtrace;
+ backtrace_symbols;
+ backtrace_symbols_fd;
+ backtrace_symbols_fmt;
+ backtrace_symbols_fd_fmt;
+ local:
+ *;
+};
--- /dev/null
+.\" $OpenBSD: backtrace.3,v 1.1 2021/06/09 19:37:43 mortimer Exp $
+.\"
+.\" Copyright (c) 2021 Todd Mortimer <mortimer@openbsd.org>
+.\" Copyright (c) 2012 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Christos Zoulas
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd November 5, 2015
+.Dt BACKTRACE 3
+.Os
+.Sh NAME
+.Nm backtrace ,
+.Nm backtrace_symbols ,
+.Nm backtrace_symbols_fd ,
+.Nm backtrace_symbols_fmt ,
+.Nm backtrace_symbols_fd_fmt
+.Nd fill in the backtrace of the currently executing thread
+.Sh LIBRARY
+.Lb libexecinfo
+.Sh SYNOPSIS
+.In execinfo.h
+.Ft size_t
+.Fn backtrace "void **addrlist" "size_t len"
+.Ft "char **"
+.Fn backtrace_symbols "void * const *addrlist" "size_t len"
+.Ft int
+.Fn backtrace_symbols_fd "void * const *addrlist" "size_t len" "int fd"
+.Ft "char **"
+.Fn backtrace_symbols_fmt "void * const *addrlist" "size_t len" "const char *fmt"
+.Ft int
+.Fn backtrace_symbols_fd_fmt "void * const *addrlist" "size_t len" "int fd" "const char *fmt"
+.Sh DESCRIPTION
+The
+.Fn backtrace
+function places into the array pointed by
+.Fa addrlist
+the array of the values of the program counter for each frame called up to
+.Fa len
+frames.
+The number of frames found (which can be fewer than
+.Fa len )
+is returned.
+.Pp
+The
+.Fn backtrace_symbols_fmt
+function takes an array of previously filled addresses from
+.Fn backtrace
+in
+.Fa addrlist
+of
+.Fa len
+elements, and uses
+.Fa fmt
+to format them.
+The formatting characters available are:
+.Bl -tag -width a -offset indent
+.It Dv a
+The numeric address of each element as would be printed using %p.
+.It Dv n
+The name of the nearest function symbol (smaller than the address element)
+as determined by
+.Xr dladdr 3
+.It Dv d
+The difference of the symbol address and the address element printed
+using 0x%tx.
+.It Dv D
+The difference of the symbol address and the address element printed using
++0x%tx if non-zero, or nothing if zero.
+.It Dv f
+The filename of the symbol as determined by
+.Xr dladdr 3 .
+.El
+.Pp
+The array of formatted strings is returned as a contiguous memory address which
+can be freed by a single
+.Xr free 3 .
+.Pp
+The
+.Fn backtrace_symbols
+function is equivalent of calling
+.Fn backtrace_symbols_fmt
+with a format argument of
+.Dq "%a <%n%D> at %f"
+.Pp
+The
+.Fn backtrace_symbols_fd
+and
+.Fn backtrace_symbols_fd_fmt
+are similar to the non _fd named functions, only instead of returning
+an array of strings, they print a new-line separated array of strings in
+fd, and return
+.Dv 0
+on success and
+.Dv \-1
+on failure.
+.Sh RETURN VALUES
+The
+.Fn backtrace
+function returns the number of elements that were filled in the backtrace.
+The
+.Fn backtrace_symbols
+and
+.Fn backtrace_symbols_fmt
+return a string array on success, and
+.Dv NULL
+on failure, setting
+.Va errno .
+.Sh SEE ALSO
+.Xr dladdr 3 ,
+.Sh HISTORY
+The
+.Fn backtrace
+library of functions first appeared in
+.Nx 7.0
+and was imported into
+.Ox 7.0 .
+.Sh BUGS
+.Bl -enum
+.It
+Only unwinding with libunwind is supported.
+On architectures without libunwind the
+.Fn backtrace
+function simply returns 0.
+.It
+Since
+.Xr dladdr 3
+only deals with dynamic symbols, local symbols from the main
+portion of the program are not printed.
+.El
--- /dev/null
+/* $OpenBSD: backtrace.c,v 1.1 2021/06/09 19:37:43 mortimer Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+
+#include "execinfo.h"
+
+static int
+rasprintf(char **buf, size_t *bufsiz, size_t offs, const char *fmt, ...)
+{
+ for (;;) {
+ size_t nbufsiz;
+ char *nbuf;
+
+ if (*buf && offs < *bufsiz) {
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(*buf + offs, *bufsiz - offs, fmt, ap);
+ va_end(ap);
+
+ if (len < 0 || (size_t)len + 1 < *bufsiz - offs)
+ return len;
+ nbufsiz = MAX(*bufsiz + 512, (size_t)len + 1);
+ } else
+ nbufsiz = MAX(offs, *bufsiz) + 512;
+
+ nbuf = realloc(*buf, nbufsiz);
+ if (nbuf == NULL)
+ return -1;
+ *buf = nbuf;
+ *bufsiz = nbufsiz;
+ }
+}
+
+/*
+ * format specifiers:
+ * %a = address
+ * %n = symbol_name
+ * %d = symbol_address - address
+ * %D = if symbol_address == address "" else +%d
+ * %f = filename
+ */
+static ssize_t
+format_string(char **buf, size_t *bufsiz, size_t offs, const char *fmt,
+ Dl_info *dli, const void *addr)
+{
+ ptrdiff_t diff = (const char *)addr - (const char *)dli->dli_saddr;
+ size_t o = offs;
+ int len;
+
+ for (; *fmt; fmt++) {
+ if (*fmt != '%')
+ goto printone;
+ switch (*++fmt) {
+ case 'a':
+ len = rasprintf(buf, bufsiz, o, "%p", addr);
+ break;
+ case 'n':
+ len = rasprintf(buf, bufsiz, o, "%s", dli->dli_sname);
+ break;
+ case 'D':
+ if (diff)
+ len = rasprintf(buf, bufsiz, o, "+0x%tx", diff);
+ else
+ len = 0;
+ break;
+ case 'd':
+ len = rasprintf(buf, bufsiz, o, "0x%tx", diff);
+ break;
+ case 'f':
+ len = rasprintf(buf, bufsiz, o, "%s", dli->dli_fname);
+ break;
+ default:
+ printone:
+ len = rasprintf(buf, bufsiz, o, "%c", *fmt);
+ break;
+ }
+ if (len == -1)
+ return -1;
+ o += len;
+ }
+ return o - offs;
+}
+
+static ssize_t
+format_address(char **buf, size_t *bufsiz, size_t offs,
+ const char *fmt, const void *addr)
+{
+ Dl_info dli;
+
+ memset(&dli, 0, sizeof(dli));
+ (void)dladdr(addr, &dli);
+
+ if (dli.dli_sname == NULL)
+ dli.dli_sname = "???";
+ if (dli.dli_fname == NULL)
+ dli.dli_fname = "???";
+ if (dli.dli_saddr == NULL)
+ dli.dli_saddr = (void *)(intptr_t)addr;
+
+ return format_string(buf, bufsiz, offs, fmt, &dli, addr);
+}
+
+char **
+backtrace_symbols_fmt(void *const *trace, size_t len, const char *fmt)
+{
+
+ static const size_t slen = sizeof(char *) + 64; /* estimate */
+ char *ptr;
+
+ if ((ptr = calloc(len, slen)) == NULL)
+ goto out;
+
+ size_t psize = len * slen;
+ size_t offs = len * sizeof(char *);
+
+ /* We store only offsets in the first pass because of realloc */
+ for (size_t i = 0; i < len; i++) {
+ ssize_t x;
+ ((char **)(void *)ptr)[i] = (void *)offs;
+ x = format_address(&ptr, &psize, offs, fmt, trace[i]);
+ if (x == -1) {
+ free(ptr);
+ ptr = NULL;
+ goto out;
+ }
+ offs += x;
+ ptr[offs++] = '\0';
+ assert(offs < psize);
+ }
+
+ /* Change offsets to pointers */
+ for (size_t j = 0; j < len; j++)
+ ((char **)(void *)ptr)[j] += (intptr_t)ptr;
+
+out:
+ return (void *)ptr;
+}
+
+int
+backtrace_symbols_fd_fmt(void *const *trace, size_t len, int fd,
+ const char *fmt)
+{
+ char **s = backtrace_symbols_fmt(trace, len, fmt);
+ if (s == NULL)
+ return -1;
+ for (size_t i = 0; i < len; i++)
+ if (dprintf(fd, "%s\n", s[i]) < 0)
+ break;
+ free(s);
+ return 0;
+}
+
+static const char fmt[] = "%a <%n%D> at %f";
+
+char **
+backtrace_symbols(void *const *trace, size_t len)
+{
+ return backtrace_symbols_fmt(trace, len, fmt);
+}
+
+int
+backtrace_symbols_fd(void *const *trace, size_t len, int fd)
+{
+ return backtrace_symbols_fd_fmt(trace, len, fd, fmt);
+}
--- /dev/null
+/* $OpenBSD: builtin.c,v 1.1 2021/06/09 19:37:43 mortimer Exp $ */
+
+/*
+ * Copyright (c) 2021 Todd Mortimer <mortimer@openbsd.org>
+ *
+ * Permission to use, copy, modify, and 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.
+ */
+
+#include "execinfo.h"
+
+size_t
+backtrace(void **trace, size_t len)
+{
+ return 0;
+}
--- /dev/null
+/* $OpenBSD: execinfo.h,v 1.1 2021/06/09 19:37:43 mortimer Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EXECINFO_H_
+#define _EXECINFO_H_
+
+#include <sys/cdefs.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+size_t backtrace(void **, size_t);
+char **backtrace_symbols(void *const *, size_t);
+int backtrace_symbols_fd(void *const *, size_t, int);
+char **backtrace_symbols_fmt(void *const *, size_t, const char *);
+int backtrace_symbols_fd_fmt(void *const *, size_t, int, const char *);
+__END_DECLS
+
+#endif /* _EXECINFO_H_ */
--- /dev/null
+# $OpenBSD: shlib_version,v 1.1 2021/06/09 19:37:43 mortimer Exp $
+major=3
+minor=0
--- /dev/null
+/* $OpenBSD: unwind.c,v 1.1 2021/06/09 19:37:43 mortimer Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdio.h>
+
+#include <unwind.h>
+#include "execinfo.h"
+
+struct tracer_context {
+ void **arr;
+ size_t len;
+ size_t n;
+};
+
+static _Unwind_Reason_Code
+tracer(struct _Unwind_Context *ctx, void *arg)
+{
+ struct tracer_context *t = arg;
+ if (t->n == (size_t)~0) {
+ /* Skip backtrace frame */
+ t->n = 0;
+ return 0;
+ }
+ if (t->n < t->len)
+ t->arr[t->n++] = (void *)_Unwind_GetIP(ctx);
+ else
+ return _URC_FOREIGN_EXCEPTION_CAUGHT;
+ return 0;
+}
+
+size_t
+backtrace(void **arr, size_t len)
+{
+ struct tracer_context ctx;
+
+ ctx.arr = arr;
+ ctx.len = len;
+ ctx.n = (size_t)~0;
+
+ _Unwind_Backtrace(tracer, &ctx);
+ if (ctx.n == (size_t)~0)
+ ctx.n = 0;
+ else if (ctx.n > 0)
+ ctx.arr[--ctx.n] = NULL; /* Skip frame below __start */
+
+ return ctx.n;
+}