diff options
author | marcel <marcel@FreeBSD.org> | 2002-04-13 04:06:34 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2002-04-13 04:06:34 +0000 |
commit | 7de93ed35cdff761e58d26c02da357d4b951a077 (patch) | |
tree | 779532ffbc1ee5a25ba782e23f2dca879455f264 /lib/libc | |
parent | 2d36550df1736dde3e073f8f924a101ae9ec90c1 (diff) | |
download | FreeBSD-src-7de93ed35cdff761e58d26c02da357d4b951a077.zip FreeBSD-src-7de93ed35cdff761e58d26c02da357d4b951a077.tar.gz |
Implement _Unwind_FindTableEntry(). This function is part of GCC
for some configurations, but not for FreeBSD (yet?). Have one in
libc in the mean time.
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/ia64/gen/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/libc/ia64/gen/unwind.c | 126 |
2 files changed, 130 insertions, 0 deletions
diff --git a/lib/libc/ia64/gen/Makefile.inc b/lib/libc/ia64/gen/Makefile.inc index 4f5dd40..34a96ef 100644 --- a/lib/libc/ia64/gen/Makefile.inc +++ b/lib/libc/ia64/gen/Makefile.inc @@ -5,3 +5,7 @@ SRCS+= sigsetjmp.S fpsetmask.c fpgetmask.c SRCS+= __divdi3.S __divsi3.S __moddi3.S __modsi3.S SRCS+= __udivdi3.S __udivsi3.S __umoddi3.S __umodsi3.S SRCS+= __divdf3.S __divsf3.S + +# The following may go away if function _Unwind_FindTableEntry() +# will be part of GCC. +SRCS+= unwind.c diff --git a/lib/libc/ia64/gen/unwind.c b/lib/libc/ia64/gen/unwind.c new file mode 100644 index 0000000..566d113 --- /dev/null +++ b/lib/libc/ia64/gen/unwind.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2002 Marcel Moolenaar + * 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 AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> + +#include <assert.h> +#include <dlfcn.h> +#include <stdlib.h> + +#include <machine/elf.h> + +#ifndef PT_IA_64_UNWIND +#define PT_IA_64_UNWIND 0x70000001 +#endif + +#define SANITY 0 + +struct ia64_unwind_entry +{ + Elf64_Addr start; + Elf64_Addr end; + Elf64_Addr descr; +}; + +struct ia64_unwind_entry * +_Unwind_FindTableEntry(const void *pc, unsigned long *pseg, unsigned long *pgp) +{ + Dl_info info; + Elf_Dyn *dyn; + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + char *p, *p_top; + struct ia64_unwind_entry *unw, *res; + register unsigned long gp __asm__("gp"); /* XXX assumes gcc */ + size_t l, m, r; + + if (!dladdr(pc, &info)) + return NULL; + + ehdr = (Elf_Ehdr*)info.dli_fbase; + +#if SANITY + assert(IS_ELF(*ehdr)); + assert(ehdr->e_ident[EI_CLASS] == ELFCLASS64); + assert(ehdr->e_ident[EI_DATA] == ELFDATA2LSB); + assert(ehdr->e_machine == EM_IA_64); +#endif + + *pgp = gp; + *pseg = 0UL; + res = NULL; + + p = (char*)info.dli_fbase + ehdr->e_phoff; + p_top = p + ehdr->e_phnum * ehdr->e_phentsize; + while (p < p_top) { + phdr = (Elf_Phdr*)p; + + switch (phdr->p_type) { + case PT_DYNAMIC: + dyn = (Elf_Dyn*)phdr->p_vaddr; + while (dyn->d_tag != DT_NULL) { + if (dyn->d_tag == DT_PLTGOT) { + *pgp = dyn->d_un.d_ptr; + break; + } + dyn++; + } + break; + case PT_LOAD: + if (pc >= (void*)phdr->p_vaddr && + pc < (void*)(phdr->p_vaddr + phdr->p_memsz)) + *pseg = phdr->p_vaddr; + break; + case PT_IA_64_UNWIND: +#if SANITY + assert(*pseg != 0UL); + assert(res == NULL); +#endif + unw = (struct ia64_unwind_entry*)phdr->p_vaddr; + l = 0; + r = phdr->p_memsz / sizeof(struct ia64_unwind_entry); + while (l < r) { + m = (l + r) >> 1; + res = unw + m; + if (pc < (void*)(res->start + *pseg)) + r = m; + else if (pc >= (void*)(res->end + *pseg)) + l = m + 1; + else + break; /* found */ + } + if (l >= r) + res = NULL; + break; + } + + p += ehdr->e_phentsize; + } + + return res; +} |