]>
Commit | Line | Data |
---|---|---|
99dee823 | 1 | /* Copyright (C) 2000-2021 Free Software Foundation, Inc. |
fee0225a RH |
2 | Contributed by Richard Henderson <rth@cygnus.com>. |
3 | ||
3bed2930 | 4 | This file is part of GCC. |
fee0225a | 5 | |
3bed2930 | 6 | GCC is free software; you can redistribute it and/or modify |
fee0225a | 7 | it under the terms of the GNU General Public License as published by |
748086b7 | 8 | the Free Software Foundation; either version 3, or (at your option) |
fee0225a RH |
9 | any later version. |
10 | ||
3bed2930 | 11 | GCC is distributed in the hope that it will be useful, |
fee0225a RH |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
748086b7 JJ |
16 | Under Section 7 of GPL version 3, you are granted additional |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | You should have received a copy of the GNU General Public License and | |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
fee0225a RH |
24 | |
25 | /* Locate the FDE entry for a given address, using glibc ld.so routines | |
26 | to avoid register/deregister calls at DSO load/unload. */ | |
27 | ||
a734f2a3 | 28 | #ifndef _GNU_SOURCE |
634879c8 | 29 | #define _GNU_SOURCE 1 |
a734f2a3 JJ |
30 | #endif |
31 | #include "config.h" | |
32 | #include <stddef.h> | |
fee0225a RH |
33 | #include <stdlib.h> |
34 | #include <link.h> | |
2a1ee410 | 35 | #include "unwind-ia64.h" |
fee0225a | 36 | |
a734f2a3 JJ |
37 | #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \ |
38 | || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG)) | |
39 | # error You need GLIBC 2.2.4 or later on IA-64 Linux | |
40 | #endif | |
fee0225a | 41 | |
a734f2a3 JJ |
42 | struct unw_ia64_callback_data |
43 | { | |
44 | Elf64_Addr pc; | |
45 | unsigned long *segment_base; | |
46 | unsigned long *gp; | |
47 | struct unw_table_entry *ret; | |
48 | }; | |
fee0225a | 49 | |
a734f2a3 JJ |
50 | static int |
51 | _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) | |
fee0225a | 52 | { |
a734f2a3 JJ |
53 | struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr; |
54 | const Elf64_Phdr *phdr, *p_unwind, *p_dynamic; | |
fee0225a RH |
55 | long n, match; |
56 | Elf64_Addr load_base, seg_base; | |
2a1ee410 | 57 | struct unw_table_entry *f_base, *f; |
cd5c4048 | 58 | size_t lo, hi; |
fee0225a | 59 | |
a734f2a3 JJ |
60 | /* Make sure struct dl_phdr_info is at least as big as we need. */ |
61 | if (size < offsetof (struct dl_phdr_info, dlpi_phnum) | |
62 | + sizeof (info->dlpi_phnum)) | |
63 | return -1; | |
fee0225a RH |
64 | |
65 | match = 0; | |
a734f2a3 JJ |
66 | phdr = info->dlpi_phdr; |
67 | load_base = info->dlpi_addr; | |
fee0225a | 68 | p_unwind = NULL; |
2a1ee410 | 69 | p_dynamic = NULL; |
a734f2a3 | 70 | seg_base = ~(Elf64_Addr) 0; |
fee0225a RH |
71 | |
72 | /* See if PC falls into one of the loaded segments. Find the unwind | |
73 | segment at the same time. */ | |
a734f2a3 | 74 | for (n = info->dlpi_phnum; --n >= 0; phdr++) |
fee0225a RH |
75 | { |
76 | if (phdr->p_type == PT_LOAD) | |
77 | { | |
78 | Elf64_Addr vaddr = phdr->p_vaddr + load_base; | |
a734f2a3 | 79 | if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz) |
fee0225a | 80 | match = 1; |
a734f2a3 JJ |
81 | if (vaddr < seg_base) |
82 | seg_base = vaddr; | |
fee0225a RH |
83 | } |
84 | else if (phdr->p_type == PT_IA_64_UNWIND) | |
85 | p_unwind = phdr; | |
2a1ee410 RH |
86 | else if (phdr->p_type == PT_DYNAMIC) |
87 | p_dynamic = phdr; | |
fee0225a RH |
88 | } |
89 | if (!match || !p_unwind) | |
a734f2a3 | 90 | return 0; |
fee0225a RH |
91 | |
92 | /* Search for the FDE within the unwind segment. */ | |
fee0225a | 93 | |
2a1ee410 | 94 | f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base); |
cd5c4048 | 95 | lo = 0; |
2a1ee410 | 96 | hi = p_unwind->p_memsz / sizeof (struct unw_table_entry); |
cd5c4048 RH |
97 | |
98 | while (lo < hi) | |
99 | { | |
100 | size_t mid = (lo + hi) / 2; | |
cd5c4048 | 101 | |
2a1ee410 | 102 | f = f_base + mid; |
a734f2a3 | 103 | if (data->pc < f->start_offset + seg_base) |
cd5c4048 | 104 | hi = mid; |
a734f2a3 | 105 | else if (data->pc >= f->end_offset + seg_base) |
cd5c4048 RH |
106 | lo = mid + 1; |
107 | else | |
2a1ee410 | 108 | goto found; |
cd5c4048 | 109 | } |
275b60d6 JJ |
110 | /* No need to search for further libraries when we know pc is contained |
111 | in this library. */ | |
112 | return 1; | |
2a1ee410 RH |
113 | |
114 | found: | |
a734f2a3 JJ |
115 | *data->segment_base = seg_base; |
116 | *data->gp = 0; | |
117 | data->ret = f; | |
2a1ee410 RH |
118 | |
119 | if (p_dynamic) | |
120 | { | |
9e4f94de | 121 | /* For dynamically linked executables and shared libraries, |
2a1ee410 RH |
122 | DT_PLTGOT is the gp value for that object. */ |
123 | Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base); | |
124 | for (; dyn->d_tag != DT_NULL ; dyn++) | |
125 | if (dyn->d_tag == DT_PLTGOT) | |
126 | { | |
a734f2a3 JJ |
127 | /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */ |
128 | *data->gp = dyn->d_un.d_ptr; | |
2a1ee410 RH |
129 | break; |
130 | } | |
131 | } | |
132 | else | |
133 | { | |
134 | /* Otherwise this is a static executable with no _DYNAMIC. | |
135 | The gp is constant program-wide. */ | |
136 | register unsigned long gp __asm__("gp"); | |
a734f2a3 | 137 | *data->gp = gp; |
2a1ee410 RH |
138 | } |
139 | ||
a734f2a3 | 140 | return 1; |
fee0225a RH |
141 | } |
142 | ||
2a1ee410 RH |
143 | /* Return a pointer to the unwind table entry for the function |
144 | containing PC. */ | |
145 | ||
146 | struct unw_table_entry * | |
9e916de7 | 147 | _Unwind_FindTableEntry (void *pc, unw_word *segment_base, unw_word *gp, |
b874a90d | 148 | struct unw_table_entry *ent ATTRIBUTE_UNUSED) |
fee0225a | 149 | { |
a734f2a3 | 150 | struct unw_ia64_callback_data data; |
fee0225a | 151 | |
a734f2a3 JJ |
152 | data.pc = (Elf64_Addr) pc; |
153 | data.segment_base = segment_base; | |
154 | data.gp = gp; | |
155 | data.ret = NULL; | |
fee0225a | 156 | |
a734f2a3 JJ |
157 | if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0) |
158 | return NULL; | |
fee0225a | 159 | |
a734f2a3 | 160 | return data.ret; |
fee0225a | 161 | } |