diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-09-17 20:13:49 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-09-17 20:13:49 +0000 |
commit | 769adf710329272785e881899510f35faed0c7a0 (patch) | |
tree | b33d7da45558c32a736c87803688ec7bfb682370 /lib | |
parent | 72b1565d8b4c9380466a40a16047d4c7eef14f79 (diff) |
Add an interface to find the ARM.exidx table for use by the ARM EHABI unwinder.
Makes exceptions work in C++ code work again om armv7.
ok guenther@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/arch/arm/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/libc/arch/arm/Symbols.list | 4 | ||||
-rw-r--r-- | lib/libc/arch/arm/dlfcn/Makefile.inc | 5 | ||||
-rw-r--r-- | lib/libc/arch/arm/dlfcn/exidx.c | 75 | ||||
-rw-r--r-- | lib/libc/shlib_version | 2 |
5 files changed, 88 insertions, 2 deletions
diff --git a/lib/libc/arch/arm/Makefile.inc b/lib/libc/arch/arm/Makefile.inc index 3347bcd9a54..a20ce0c317e 100644 --- a/lib/libc/arch/arm/Makefile.inc +++ b/lib/libc/arch/arm/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.6 2016/05/07 19:05:21 guenther Exp $ +# $OpenBSD: Makefile.inc,v 1.7 2016/09/17 20:13:48 kettenis Exp $ # $NetBSD: Makefile.inc,v 1.5 2002/07/10 04:29:06 thorpej Exp $ .include <bsd.own.mk> @@ -9,3 +9,5 @@ CPPFLAGS += -DSOFTFLOAT SOFTFLOAT_BITS=32 .include <arch/arm/softfloat/Makefile.inc> + +.include <arch/arm/dlfcn/Makefile.inc> diff --git a/lib/libc/arch/arm/Symbols.list b/lib/libc/arch/arm/Symbols.list index 26b3ee1a5b1..3401e5e20f5 100644 --- a/lib/libc/arch/arm/Symbols.list +++ b/lib/libc/arch/arm/Symbols.list @@ -85,3 +85,7 @@ shortShift64Left shortShift96Left sub64 sub96 + +/* dlfcn */ +dl_unwind_find_exidx +__gnu_Unwind_Find_exidx diff --git a/lib/libc/arch/arm/dlfcn/Makefile.inc b/lib/libc/arch/arm/dlfcn/Makefile.inc new file mode 100644 index 00000000000..d0ada6a2360 --- /dev/null +++ b/lib/libc/arch/arm/dlfcn/Makefile.inc @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile.inc,v 1.1 2016/09/17 20:13:48 kettenis Exp $ + +SRCS += exidx.c + +.PATH: ${.CURDIR}/dlfcn diff --git a/lib/libc/arch/arm/dlfcn/exidx.c b/lib/libc/arch/arm/dlfcn/exidx.c new file mode 100644 index 00000000000..5f012edbc0a --- /dev/null +++ b/lib/libc/arch/arm/dlfcn/exidx.c @@ -0,0 +1,75 @@ +/* $OpenBSD: exidx.c,v 1.1 2016/09/17 20:13:48 kettenis Exp $ */ +/* + * Copyright (c) 2016 Mark Kettenis <kettenis@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 <sys/types.h> +#include <link.h> + +void *dl_unwind_find_exidx(const void *pc, int *pcount) __attribute__((weak)); + +struct exidx_data { + u_long pc; + void *exidx; + int *pcount; +}; + +struct exidx_entry { + uint32_t data[2]; +}; + +static int +find_exidx(struct dl_phdr_info *info, size_t size, void *p) +{ + struct exidx_data *data = p; + const Elf_Phdr *phdr; + void *exidx; + int count = 0; + int found = 0; + int i; + + for (i = 0; i < info->dlpi_phnum; i++) { + phdr = &info->dlpi_phdr[i]; + if (data->pc >= info->dlpi_addr + phdr->p_vaddr && + data->pc < info->dlpi_addr + phdr->p_vaddr + phdr->p_memsz) + found = 1; + if (phdr->p_type == PT_ARM_EXIDX) { + exidx = (void *)(info->dlpi_addr + phdr->p_vaddr); + count = phdr->p_memsz / sizeof(struct exidx_entry); + } + } + + if (found && count > 0) { + data->exidx = exidx; + *data->pcount = count; + return 1; + } + + return 0; +} + +void * +dl_unwind_find_exidx(const void *pc, int *pcount) +{ + struct exidx_data data; + + data.pc = (u_long)pc; + data.pcount = pcount; + if (dl_iterate_phdr(find_exidx, &data)) + return data.exidx; + return NULL; +} + +__strong_alias(__gnu_Unwind_Find_exidx, dl_unwind_find_exidx); diff --git a/lib/libc/shlib_version b/lib/libc/shlib_version index 08c19ac1165..4821cfc2bd0 100644 --- a/lib/libc/shlib_version +++ b/lib/libc/shlib_version @@ -1,4 +1,4 @@ major=89 -minor=1 +minor=2 # note: If changes were made to include/thread_private.h or if system # calls were added/changed then librthread/shlib_version also be updated. |