]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libc/ia64/gen/unwind.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / libc / ia64 / gen / unwind.c
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
43 struct ia64_unwind_entry
44 {
45         Elf64_Addr start;
46         Elf64_Addr end;
47         Elf64_Addr descr;
48 };
49
50 struct 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 }