Module Name:    src
Committed By:   christos
Date:           Sat May 26 22:02:29 UTC 2012

Added Files:
        src/lib/libexecinfo: Makefile backtrace.3 backtrace.c builtin.c
            execinfo.h shlib_version symtab.c symtab.h unwind.c unwind.h

Log Message:
Add a similar to linux backtrace_* and execinfo.h family of functions


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/lib/libexecinfo/Makefile \
    src/lib/libexecinfo/backtrace.3 src/lib/libexecinfo/backtrace.c \
    src/lib/libexecinfo/builtin.c src/lib/libexecinfo/execinfo.h \
    src/lib/libexecinfo/shlib_version src/lib/libexecinfo/symtab.c \
    src/lib/libexecinfo/symtab.h src/lib/libexecinfo/unwind.c \
    src/lib/libexecinfo/unwind.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/lib/libexecinfo/Makefile
diff -u /dev/null src/lib/libexecinfo/Makefile:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/Makefile	Sat May 26 18:02:29 2012
@@ -0,0 +1,31 @@
+# $NetBSD: Makefile,v 1.1 2012/05/26 22:02:29 christos Exp $
+
+.include <bsd.own.mk>
+
+USE_UNWIND=yes
+WARNS?=4
+INCSDIR=/usr/include
+INCS=execinfo.h
+
+#CPPFLAGS+='-D__RCSID(a)=' -D_GNU_SOURCE '-D__printflike(a,b)='
+#CPPFLAGS+=-I/usr/include/libelf
+#COPTS+=-std=gnu99
+
+LIBDPLIBS+= elf	${NETBSDSRCDIR}/external/bsd/libelf/lib
+
+LIB=execinfo
+SRCS=symtab.c backtrace.c
+MAN= backtrace.3
+
+.if ${USE_UNWIND} == "yes"
+SRCS+=unwind.c
+.else
+SRCS+=builtin.c
+.endif
+
+MLINKS+= backtrace.3 backtrace_symbols.3
+MLINKS+= backtrace.3 backtrace_symbols_fmt.3
+MLINKS+= backtrace.3 backtrace_symbols_fd.3
+MLINKS+= backtrace.3 backtrace_symbols_fd_fmt.3
+
+.include <bsd.lib.mk>
Index: src/lib/libexecinfo/backtrace.3
diff -u /dev/null src/lib/libexecinfo/backtrace.3:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/backtrace.3	Sat May 26 18:02:29 2012
@@ -0,0 +1,161 @@
+.\"	$NetBSD: backtrace.3,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.
+.\"
+.Dd January 24, 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 .
+.\" XXX
+Diagnostic output may also be produced, by the ELF symbol lookup functions.
+function returns a pointer to a string that is the parent directory of
+.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 be part of libc/libutil so that library
+dependencies are not 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 to find it
+which is not portable.
+.El
+.Sh SEE ALSO
+.Xr elf 3
+.Xr dladdr 3
+.Sh HISTORY
+The
+.Fn backtrace
+library of functions first appeared in
+.Nx 6 .
Index: src/lib/libexecinfo/backtrace.c
diff -u /dev/null src/lib/libexecinfo/backtrace.c:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/backtrace.c	Sat May 26 18:02:29 2012
@@ -0,0 +1,227 @@
+/*	$NetBSD: backtrace.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: backtrace.c,v 1.1 2012/05/26 22:02:29 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)
+		return NULL;
+
+	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);
+			return NULL;
+		}
+		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;
+
+	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);
+}
Index: src/lib/libexecinfo/builtin.c
diff -u /dev/null src/lib/libexecinfo/builtin.c:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/builtin.c	Sat May 26 18:02:29 2012
@@ -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;
+}
Index: src/lib/libexecinfo/execinfo.h
diff -u /dev/null src/lib/libexecinfo/execinfo.h:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/execinfo.h	Sat May 26 18:02:29 2012
@@ -0,0 +1,42 @@
+/*	$NetBSD: execinfo.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 _EXECINFO_H_
+#define _EXECINFO_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_ */
Index: src/lib/libexecinfo/shlib_version
diff -u /dev/null src/lib/libexecinfo/shlib_version:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/shlib_version	Sat May 26 18:02:29 2012
@@ -0,0 +1,3 @@
+#	$NetBSD: shlib_version,v 1.1 2012/05/26 22:02:29 christos Exp $
+major=0
+minor=0
Index: src/lib/libexecinfo/symtab.c
diff -u /dev/null src/lib/libexecinfo/symtab.c:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/symtab.c	Sat May 26 18:02:29 2012
@@ -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;
+}
Index: src/lib/libexecinfo/symtab.h
diff -u /dev/null src/lib/libexecinfo/symtab.h:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/symtab.h	Sat May 26 18:02:29 2012
@@ -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_ */
Index: src/lib/libexecinfo/unwind.c
diff -u /dev/null src/lib/libexecinfo/unwind.c:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/unwind.c	Sat May 26 18:02:29 2012
@@ -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;
+}
Index: src/lib/libexecinfo/unwind.h
diff -u /dev/null src/lib/libexecinfo/unwind.h:1.1
--- /dev/null	Sat May 26 18:02:29 2012
+++ src/lib/libexecinfo/unwind.h	Sat May 26 18:02:29 2012
@@ -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_ */

Reply via email to