1/* 2 * Copyright (c) 2002 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29#include <sys/types.h> 30 31#include <assert.h> 32#include <dlfcn.h> 33#include <stdlib.h> 34 35#include <machine/elf.h> 36 37#ifndef PT_IA_64_UNWIND 38#define PT_IA_64_UNWIND 0x70000001 39#endif 40 41#define SANITY 0 42 43struct ia64_unwind_entry 44{ 45 Elf64_Addr start; 46 Elf64_Addr end; 47 Elf64_Addr descr; 48}; 49 50struct ia64_unwind_entry * 51_Unwind_FindTableEntry(const void *pc, unsigned long *pseg, unsigned long *pgp) 52{ 53 Dl_info info; 54 Elf_Dyn *dyn; 55 Elf_Ehdr *ehdr; 56 Elf_Phdr *phdr; 57 char *p, *p_top; 58 struct ia64_unwind_entry *unw, *res; 59 register unsigned long gp __asm__("gp"); /* XXX assumes gcc */ 60 unsigned long reloc, vaddr; 61 size_t l, m, r; 62 63 if (!dladdr(pc, &info)) 64 return NULL; 65 66 ehdr = (Elf_Ehdr*)info.dli_fbase; 67 68#if SANITY 69 assert(IS_ELF(*ehdr)); 70 assert(ehdr->e_ident[EI_CLASS] == ELFCLASS64); 71 assert(ehdr->e_ident[EI_DATA] == ELFDATA2LSB); 72 assert(ehdr->e_machine == EM_IA_64); 73#endif 74 75 reloc = (ehdr->e_type == ET_DYN) ? (uintptr_t)info.dli_fbase : 0; 76 *pgp = gp; 77 *pseg = 0UL; 78 res = NULL; 79 80 p = (char*)info.dli_fbase + ehdr->e_phoff; 81 p_top = p + ehdr->e_phnum * ehdr->e_phentsize; 82 while (p < p_top) { 83 phdr = (Elf_Phdr*)p; 84 vaddr = phdr->p_vaddr + reloc; 85 86 switch (phdr->p_type) { 87 case PT_DYNAMIC: 88 dyn = (Elf_Dyn*)vaddr; 89 while (dyn->d_tag != DT_NULL) { 90 if (dyn->d_tag == DT_PLTGOT) { 91 *pgp = dyn->d_un.d_ptr + reloc; 92 break; 93 } 94 dyn++; 95 } 96 break; 97 case PT_LOAD: 98 if (pc >= (void*)vaddr && 99 pc < (void*)(vaddr + phdr->p_memsz)) 100 *pseg = vaddr; 101 break; 102 case PT_IA_64_UNWIND: 103#if SANITY 104 assert(*pseg != 0UL); 105 assert(res == NULL); 106#endif 107 unw = (struct ia64_unwind_entry*)vaddr; 108 l = 0; 109 r = phdr->p_memsz / sizeof(struct ia64_unwind_entry); 110 while (l < r) { 111 m = (l + r) >> 1; 112 res = unw + m; 113 if (pc < (void*)(res->start + *pseg)) 114 r = m; 115 else if (pc >= (void*)(res->end + *pseg)) 116 l = m + 1; 117 else 118 break; /* found */ 119 } 120 if (l >= r) 121 res = NULL; 122 break; 123 } 124 125 p += ehdr->e_phentsize; 126 } 127 128 return res; 129} 130