From: mortimer Date: Wed, 9 Jun 2021 19:37:43 +0000 (+0000) Subject: Add libexecinfo. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=771fbea0148a7fe458cf2c657edb98b32659f150;p=openbsd Add libexecinfo. Based on NetBSD implementation, without the libelf dependency. Architectures which have libunwind use libunwind, and others use a stub implementation that does nothing since __builtin methods are unreliable. Much feedback and help from jca@. ok kettenis@ sthen@ --- diff --git a/gnu/lib/libexecinfo/Makefile b/gnu/lib/libexecinfo/Makefile new file mode 100644 index 00000000000..fe0855a4552 --- /dev/null +++ b/gnu/lib/libexecinfo/Makefile @@ -0,0 +1,55 @@ +# $OpenBSD: Makefile,v 1.1 2021/06/09 19:37:43 mortimer Exp $ + +.include + +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 diff --git a/gnu/lib/libexecinfo/Symbols.map b/gnu/lib/libexecinfo/Symbols.map new file mode 100644 index 00000000000..c3ea4d69277 --- /dev/null +++ b/gnu/lib/libexecinfo/Symbols.map @@ -0,0 +1,10 @@ +{ + global: + backtrace; + backtrace_symbols; + backtrace_symbols_fd; + backtrace_symbols_fmt; + backtrace_symbols_fd_fmt; + local: + *; +}; diff --git a/gnu/lib/libexecinfo/backtrace.3 b/gnu/lib/libexecinfo/backtrace.3 new file mode 100644 index 00000000000..99ddf912a2b --- /dev/null +++ b/gnu/lib/libexecinfo/backtrace.3 @@ -0,0 +1,152 @@ +.\" $OpenBSD: backtrace.3,v 1.1 2021/06/09 19:37:43 mortimer Exp $ +.\" +.\" Copyright (c) 2021 Todd Mortimer +.\" 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 diff --git a/gnu/lib/libexecinfo/backtrace.c b/gnu/lib/libexecinfo/backtrace.c new file mode 100644 index 00000000000..c967b0e9072 --- /dev/null +++ b/gnu/lib/libexecinfo/backtrace.c @@ -0,0 +1,207 @@ +/* $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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/gnu/lib/libexecinfo/builtin.c b/gnu/lib/libexecinfo/builtin.c new file mode 100644 index 00000000000..7bc60f74ce4 --- /dev/null +++ b/gnu/lib/libexecinfo/builtin.c @@ -0,0 +1,25 @@ +/* $OpenBSD: builtin.c,v 1.1 2021/06/09 19:37:43 mortimer Exp $ */ + +/* + * Copyright (c) 2021 Todd Mortimer + * + * 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; +} diff --git a/gnu/lib/libexecinfo/execinfo.h b/gnu/lib/libexecinfo/execinfo.h new file mode 100644 index 00000000000..d0017de07dc --- /dev/null +++ b/gnu/lib/libexecinfo/execinfo.h @@ -0,0 +1,45 @@ +/* $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 +#include + +__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_ */ diff --git a/gnu/lib/libexecinfo/shlib_version b/gnu/lib/libexecinfo/shlib_version new file mode 100644 index 00000000000..1f3ecfd9521 --- /dev/null +++ b/gnu/lib/libexecinfo/shlib_version @@ -0,0 +1,3 @@ +# $OpenBSD: shlib_version,v 1.1 2021/06/09 19:37:43 mortimer Exp $ +major=3 +minor=0 diff --git a/gnu/lib/libexecinfo/unwind.c b/gnu/lib/libexecinfo/unwind.c new file mode 100644 index 00000000000..e852710c500 --- /dev/null +++ b/gnu/lib/libexecinfo/unwind.c @@ -0,0 +1,76 @@ +/* $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 +#include +#include + +#include +#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; +}