aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-22 16:31:19 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-22 16:31:19 +0000
commit28df74992501a9d42020f85e07ce2afe49abec32 (patch)
tree5a677e5e476387db855a8ebfe79686e3c2e084a9
downloadsrc-28df74992501a9d42020f85e07ce2afe49abec32.tar.gz
src-28df74992501a9d42020f85e07ce2afe49abec32.zip
Vendor import of NetBSD's libexecinfo at 2013-08-22vendor/NetBSD/libexecinfo/20130822
Notes
Notes: svn path=/vendor/NetBSD/libexecinfo/dist/; revision=254661 svn path=/vendor/NetBSD/libexecinfo/20130822/; revision=254662; tag=vendor/NetBSD/libexecinfo/20130822
-rw-r--r--backtrace.3159
-rw-r--r--backtrace.c229
-rw-r--r--builtin.c68
-rw-r--r--execinfo.h44
-rw-r--r--symtab.c192
-rw-r--r--symtab.h42
-rw-r--r--unwind.c72
-rw-r--r--unwind.h68
-rw-r--r--unwind_arm_ehabi_stub.c61
9 files changed, 935 insertions, 0 deletions
diff --git a/backtrace.3 b/backtrace.3
new file mode 100644
index 000000000000..781dc6e065db
--- /dev/null
+++ b/backtrace.3
@@ -0,0 +1,159 @@
+.\" $NetBSD: backtrace.3,v 1.4 2012/06/10 00:24:36 christos 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.
+.\"
+.Dd May 26, 2012
+.Dt BACKTRACE 3
+.Os
+.Sh NAME
+.Nm backtrace
+.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_fmt_fd "void * const *addrlist" "size_t len" "const char *fmt" "int fd"
+.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
+if the symbol was dynamic, or looked up in the executable if static and
+the /proc filesystem is available to determine the executable path.
+.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 addresss 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
+.Dv "%a <%n%D> at %f"
+.Pp
+The
+.Fn backtrace_symbols_fd
+and
+.Fn backtrace_symbols_fmt_fd
+are similar to the non _fd named functions, only instead of returning
+an array or 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 tht 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 .
+Diagnostic output may also be produced by the ELF symbol lookup functions.
+.Sh SEE ALSO
+.Xr dladdr 3 ,
+.Xr elf 3
+.Sh HISTORY
+The
+.Fn backtrace
+library of functions first appeared in
+.Nx 7.0 .
+.Sh BUGS
+.Bl -enum
+.It
+Errors should not be printed but communicated to the caller differently.
+.It
+Because these functions use
+.Xr elf 3
+this is a separate library instead of being part of libc/libutil
+so that no library dependencies are introduced.
+.It
+The Linux versions of the functions (there are no _fmt variants) use
+.Ft int
+instead of
+.Ft size_t
+arguments.
+.It
+Since
+.Xr dladdr 3
+only deals with dynamic symbols, we need to find the symbols from the main
+portion of the program.
+For that we need to locate the executable, and we use procfs for
+finding it, which is not portable.
+.El
diff --git a/backtrace.c b/backtrace.c
new file mode 100644
index 000000000000..02ad1480372c
--- /dev/null
+++ b/backtrace.c
@@ -0,0 +1,229 @@
+/* $NetBSD: backtrace.c,v 1.2 2012/07/09 03:11:59 christos 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>
+__RCSID("$NetBSD: backtrace.c,v 1.2 2012/07/09 03:11:59 christos Exp $");
+
+#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 <elf.h>
+
+#include "execinfo.h"
+#include "symtab.h"
+
+#ifdef __linux__
+#define SELF "/proc/self/exe"
+#else
+#define SELF "/proc/curproc/file"
+#endif
+
+static int __printflike(4, 5)
+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 < *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(symtab_t *st, 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 (st)
+ symtab_find(st, 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;
+ symtab_t *st;
+ int fd;
+
+ if ((fd = open(SELF, O_RDONLY)) != -1)
+ st = symtab_create(fd, -1, STT_FUNC);
+ else
+ st = NULL;
+
+ 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(st, &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:
+ symtab_destroy(st);
+ if (fd != -1)
+ (void)close(fd);
+
+ 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/builtin.c b/builtin.c
new file mode 100644
index 000000000000..3fc861958d15
--- /dev/null
+++ b/builtin.c
@@ -0,0 +1,68 @@
+/* $NetBSD: builtin.c,v 1.1 2012/05/26 22:02:29 christos 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>
+__RCSID("$NetBSD: builtin.c,v 1.1 2012/05/26 22:02:29 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include "execinfo.h"
+
+#ifdef __MACHINE_STACK_GROWS_UP
+#define BELOW >
+#else
+#define BELOW <
+#endif
+
+#ifdef __lint__
+#define __builtin_frame_address(a) ((void *)a)
+#endif
+
+struct frameinfo {
+ struct frameinfo *next;
+ void *return_address;
+};
+
+size_t
+backtrace(void **trace, size_t len)
+{
+ const struct frameinfo *frame = __builtin_frame_address(0);
+ void *stack = &stack;
+
+ for (size_t i = 0; i < len; i++) {
+ if ((const void *)frame BELOW stack)
+ return i;
+ trace[i] = frame->return_address;
+ frame = frame->next;
+ }
+
+ return len;
+}
diff --git a/execinfo.h b/execinfo.h
new file mode 100644
index 000000000000..0ea529e80ccd
--- /dev/null
+++ b/execinfo.h
@@ -0,0 +1,44 @@
+/* $NetBSD: execinfo.h,v 1.2 2012/06/09 21:22:17 christos 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 <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_ */
diff --git a/symtab.c b/symtab.c
new file mode 100644
index 000000000000..b5da75cefad7
--- /dev/null
+++ b/symtab.c
@@ -0,0 +1,192 @@
+/* $NetBSD: symtab.c,v 1.1 2012/05/26 22:02:29 christos 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>
+__RCSID("$NetBSD: symtab.c,v 1.1 2012/05/26 22:02:29 christos Exp $");
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <err.h>
+#include <dlfcn.h>
+
+#include <libelf.h>
+#include <gelf.h>
+#ifndef ELF_ST_BIND
+#define ELF_ST_BIND(x) ((x) >> 4)
+#endif
+#ifndef ELF_ST_TYPE
+#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf)
+#endif
+
+
+#include "symtab.h"
+
+struct symbol {
+ char *st_name;
+ uintptr_t st_value;
+ uintptr_t st_info;
+};
+
+struct symtab {
+ size_t nsymbols;
+ struct symbol *symbols;
+};
+
+static int
+address_compare(const void *a, const void *b)
+{
+ const struct symbol *sa = a;
+ const struct symbol *sb = b;
+ return (int)(intmax_t)(sa->st_value - sb->st_value);
+}
+
+void
+symtab_destroy(symtab_t *s)
+{
+ if (s == NULL)
+ return;
+ for (size_t i = 0; i < s->nsymbols; i++)
+ free(s->symbols[i].st_name);
+ free(s->symbols);
+ free(s);
+}
+
+symtab_t *
+symtab_create(int fd, int bind, int type)
+{
+ Elf *elf;
+ symtab_t *st;
+ Elf_Scn *scn = NULL;
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ warnx("Elf Library is out of date.");
+ return NULL;
+ }
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (elf == NULL) {
+ warnx("Error opening elf file: %s", elf_errmsg(elf_errno()));
+ return NULL;
+ }
+ st = calloc(1, sizeof(*st));
+ if (st == NULL) {
+ warnx("Error allocating symbol table");
+ elf_end(elf);
+ return NULL;
+ }
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ GElf_Shdr shdr;
+ Elf_Data *edata;
+ size_t ns;
+ struct symbol *s;
+
+ gelf_getshdr(scn, &shdr);
+ if(shdr.sh_type != SHT_SYMTAB)
+ continue;
+
+ edata = elf_getdata(scn, NULL);
+ ns = shdr.sh_size / shdr.sh_entsize;
+ s = calloc(ns, sizeof(*s));
+ if (s == NULL) {
+ warn("Cannot allocate %zu symbols", ns);
+ goto out;
+ }
+ st->symbols = s;
+
+ for (size_t i = 0; i < ns; i++) {
+ GElf_Sym sym;
+ gelf_getsym(edata, (int)i, &sym);
+
+ if (bind != -1 &&
+ (unsigned)bind != ELF_ST_BIND(sym.st_info))
+ continue;
+
+ if (type != -1 &&
+ (unsigned)type != ELF_ST_TYPE(sym.st_info))
+ continue;
+
+ s->st_value = sym.st_value;
+ s->st_info = sym.st_info;
+ s->st_name = strdup(
+ elf_strptr(elf, shdr.sh_link, sym.st_name));
+ if (s->st_name == NULL)
+ goto out;
+ s++;
+ }
+ st->nsymbols = s - st->symbols;
+ if (st->nsymbols == 0) {
+ warnx("No symbols found");
+ goto out;
+ }
+ qsort(st->symbols, st->nsymbols, sizeof(*st->symbols),
+ address_compare);
+ elf_end(elf);
+ return st;
+ }
+out:
+ symtab_destroy(st);
+ elf_end(elf);
+ return NULL;
+}
+
+
+int
+symtab_find(const symtab_t *st, const void *p, Dl_info *dli)
+{
+ struct symbol *s = st->symbols;
+ size_t ns = st->nsymbols;
+ size_t hi = ns;
+ size_t lo = 0;
+ size_t mid = ns / 2;
+ uintptr_t dd, sd, me = (uintptr_t)p;
+
+ for (;;) {
+ if (s[mid].st_value < me)
+ lo = mid;
+ else if (s[mid].st_value > me)
+ hi = mid;
+ else
+ break;
+ if (hi - lo == 1) {
+ mid = lo;
+ break;
+ }
+ mid = (hi + lo) / 2;
+ }
+ dd = me - (uintptr_t)dli->dli_saddr;
+ sd = me - s[mid].st_value;
+ if (dd > sd) {
+ dli->dli_saddr = (void *)s[mid].st_value;
+ dli->dli_sname = s[mid].st_name;
+ }
+ return 1;
+}
diff --git a/symtab.h b/symtab.h
new file mode 100644
index 000000000000..d527a3cc4729
--- /dev/null
+++ b/symtab.h
@@ -0,0 +1,42 @@
+/* $NetBSD: symtab.h,v 1.1 2012/05/26 22:02:29 christos 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 _SYMTAB_H_
+#define _SYMTAB_H_
+
+__BEGIN_DECLS
+typedef struct symtab symtab_t;
+
+void symtab_destroy(symtab_t *);
+symtab_t * symtab_create(int, int, int);
+int symtab_find(const symtab_t *, const void *, Dl_info *);
+__END_DECLS
+
+#endif /* _SYMTAB_H_ */
diff --git a/unwind.c b/unwind.c
new file mode 100644
index 000000000000..b9b785ff6021
--- /dev/null
+++ b/unwind.c
@@ -0,0 +1,72 @@
+/* $NetBSD: unwind.c,v 1.1 2012/05/26 22:02:29 christos 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++] = _Unwind_GetIP(ctx);
+ 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)
+ ctx.arr[--ctx.n] = NULL; /* Skip frame below __start */
+
+ return ctx.n;
+}
diff --git a/unwind.h b/unwind.h
new file mode 100644
index 000000000000..c9978b3d5df5
--- /dev/null
+++ b/unwind.h
@@ -0,0 +1,68 @@
+/* $NetBSD: unwind.h,v 1.1 2012/05/26 22:02:29 christos Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 _UNWIND_H_
+#define _UNWIND_H_
+
+__BEGIN_DECLS
+struct _Unwind_Context;
+struct _Unwind_Exception;
+typedef int _Unwind_Reason_Code;
+typedef void *_Unwind_Ptr;
+typedef long _Unwind_Word;
+
+typedef _Unwind_Reason_Code
+ (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *);
+#ifdef notyet
+typedef _Unwind_Reason_Code
+ (*_Unwind_Stop_Fn)(struct _Unwind_Context *, void *);
+#endif
+
+_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
+void _Unwind_DeleteException(struct _Unwind_Exception *);
+void *_Unwind_FindEnclosingFunction(void *);
+#ifdef notyet
+_Unwind_Reason_Code _Unwind_ForcedUnwind(struct _Unwind_Exception *,
+ _Unwind_Stop_fn, void *);
+#endif
+_Unwind_Word _Unwind_GetCFA(struct _Unwind_Context *);
+_Unwind_Ptr _Unwind_GetDataRelBase(struct _Unwind_Context *);
+_Unwind_Word _Unwind_GetGR(struct _Unwind_Context *, int);
+_Unwind_Ptr _Unwind_GetIP(struct _Unwind_Context *);
+_Unwind_Ptr _Unwind_GetIPInfo(struct _Unwind_Context *, int *);
+void *_Unwind_GetLanguageSpecificData(
+ struct _Unwind_Context *);
+_Unwind_Ptr _Unwind_GetRegionStart(struct _Unwind_Context *);
+_Unwind_Ptr _Unwind_GetTextRelBase(struct _Unwind_Context *);
+_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *);
+void _Unwind_Resume(struct _Unwind_Exception *);
+_Unwind_Reason_Code _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *);
+void _Unwind_SetGR(struct _Unwind_Context *, int,
+ _Unwind_Ptr);
+void _Unwind_SetIP(struct _Unwind_Context *, _Unwind_Ptr);
+__END_DECLS
+#endif /* _UNWIND_H_ */
diff --git a/unwind_arm_ehabi_stub.c b/unwind_arm_ehabi_stub.c
new file mode 100644
index 000000000000..6fe97161edf5
--- /dev/null
+++ b/unwind_arm_ehabi_stub.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 "unwind.h"
+
+void _Unwind_VRS_Get(struct _Unwind_Context *, int, _Unwind_Word, int, void *);
+void _Unwind_VRS_Set(struct _Unwind_Context *, int, _Unwind_Word, int, void *);
+
+_Unwind_Word
+_Unwind_GetGR(struct _Unwind_Context *context, int regno)
+{
+ _Unwind_Word val;
+ _Unwind_VRS_Get(context, 0 /*_UVRSC_CORE*/, regno, 0 /*_UVRSD_UINT32*/,
+ &val);
+
+ return val;
+}
+
+_Unwind_Ptr
+_Unwind_GetIP(struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr)(_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1);
+}
+
+_Unwind_Ptr
+_Unwind_GetIPInfo(struct _Unwind_Context *context, int *p)
+{
+ *p = 0;
+ return _Unwind_GetIP(context);
+}
+
+void
+_Unwind_SetGR(struct _Unwind_Context *context, int reg, _Unwind_Ptr val)
+{
+ _Unwind_VRS_Set(context, 0 /*_UVRSC_CORE*/, reg, 0 /*_UVRSD_UINT32*/,
+ &val);
+}