]>
Commit | Line | Data |
---|---|---|
a945c346 | 1 | /* Copyright (C) 2000-2024 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" | |
cef03728 | 32 | #ifndef inhibit_libc |
a734f2a3 | 33 | #include <stddef.h> |
fee0225a RH |
34 | #include <stdlib.h> |
35 | #include <link.h> | |
2a1ee410 | 36 | #include "unwind-ia64.h" |
fee0225a | 37 | |
a734f2a3 JJ |
38 | #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \ |
39 | || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG)) | |
40 | # error You need GLIBC 2.2.4 or later on IA-64 Linux | |
41 | #endif | |
fee0225a | 42 | |
a734f2a3 JJ |
43 | struct unw_ia64_callback_data |
44 | { | |
45 | Elf64_Addr pc; | |
46 | unsigned long *segment_base; | |
47 | unsigned long *gp; | |
48 | struct unw_table_entry *ret; | |
49 | }; | |
fee0225a | 50 | |
a734f2a3 JJ |
51 | static int |
52 | _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) | |
fee0225a | 53 | { |
a734f2a3 JJ |
54 | struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr; |
55 | const Elf64_Phdr *phdr, *p_unwind, *p_dynamic; | |
fee0225a RH |
56 | long n, match; |
57 | Elf64_Addr load_base, seg_base; | |
2a1ee410 | 58 | struct unw_table_entry *f_base, *f; |
cd5c4048 | 59 | size_t lo, hi; |
fee0225a | 60 | |
a734f2a3 JJ |
61 | /* Make sure struct dl_phdr_info is at least as big as we need. */ |
62 | if (size < offsetof (struct dl_phdr_info, dlpi_phnum) | |
63 | + sizeof (info->dlpi_phnum)) | |
64 | return -1; | |
fee0225a RH |
65 | |
66 | match = 0; | |
a734f2a3 JJ |
67 | phdr = info->dlpi_phdr; |
68 | load_base = info->dlpi_addr; | |
fee0225a | 69 | p_unwind = NULL; |
2a1ee410 | 70 | p_dynamic = NULL; |
a734f2a3 | 71 | seg_base = ~(Elf64_Addr) 0; |
fee0225a RH |
72 | |
73 | /* See if PC falls into one of the loaded segments. Find the unwind | |
74 | segment at the same time. */ | |
a734f2a3 | 75 | for (n = info->dlpi_phnum; --n >= 0; phdr++) |
fee0225a RH |
76 | { |
77 | if (phdr->p_type == PT_LOAD) | |
78 | { | |
79 | Elf64_Addr vaddr = phdr->p_vaddr + load_base; | |
a734f2a3 | 80 | if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz) |
fee0225a | 81 | match = 1; |
a734f2a3 JJ |
82 | if (vaddr < seg_base) |
83 | seg_base = vaddr; | |
fee0225a RH |
84 | } |
85 | else if (phdr->p_type == PT_IA_64_UNWIND) | |
86 | p_unwind = phdr; | |
2a1ee410 RH |
87 | else if (phdr->p_type == PT_DYNAMIC) |
88 | p_dynamic = phdr; | |
fee0225a RH |
89 | } |
90 | if (!match || !p_unwind) | |
a734f2a3 | 91 | return 0; |
fee0225a RH |
92 | |
93 | /* Search for the FDE within the unwind segment. */ | |
fee0225a | 94 | |
2a1ee410 | 95 | f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base); |
cd5c4048 | 96 | lo = 0; |
2a1ee410 | 97 | hi = p_unwind->p_memsz / sizeof (struct unw_table_entry); |
cd5c4048 RH |
98 | |
99 | while (lo < hi) | |
100 | { | |
101 | size_t mid = (lo + hi) / 2; | |
cd5c4048 | 102 | |
2a1ee410 | 103 | f = f_base + mid; |
a734f2a3 | 104 | if (data->pc < f->start_offset + seg_base) |
cd5c4048 | 105 | hi = mid; |
a734f2a3 | 106 | else if (data->pc >= f->end_offset + seg_base) |
cd5c4048 RH |
107 | lo = mid + 1; |
108 | else | |
2a1ee410 | 109 | goto found; |
cd5c4048 | 110 | } |
275b60d6 JJ |
111 | /* No need to search for further libraries when we know pc is contained |
112 | in this library. */ | |
113 | return 1; | |
2a1ee410 RH |
114 | |
115 | found: | |
a734f2a3 JJ |
116 | *data->segment_base = seg_base; |
117 | *data->gp = 0; | |
118 | data->ret = f; | |
2a1ee410 RH |
119 | |
120 | if (p_dynamic) | |
121 | { | |
9e4f94de | 122 | /* For dynamically linked executables and shared libraries, |
2a1ee410 RH |
123 | DT_PLTGOT is the gp value for that object. */ |
124 | Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base); | |
125 | for (; dyn->d_tag != DT_NULL ; dyn++) | |
126 | if (dyn->d_tag == DT_PLTGOT) | |
127 | { | |
a734f2a3 JJ |
128 | /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */ |
129 | *data->gp = dyn->d_un.d_ptr; | |
2a1ee410 RH |
130 | break; |
131 | } | |
132 | } | |
133 | else | |
134 | { | |
135 | /* Otherwise this is a static executable with no _DYNAMIC. | |
136 | The gp is constant program-wide. */ | |
137 | register unsigned long gp __asm__("gp"); | |
a734f2a3 | 138 | *data->gp = gp; |
2a1ee410 RH |
139 | } |
140 | ||
a734f2a3 | 141 | return 1; |
fee0225a RH |
142 | } |
143 | ||
2a1ee410 RH |
144 | /* Return a pointer to the unwind table entry for the function |
145 | containing PC. */ | |
146 | ||
147 | struct unw_table_entry * | |
9e916de7 | 148 | _Unwind_FindTableEntry (void *pc, unw_word *segment_base, unw_word *gp, |
b874a90d | 149 | struct unw_table_entry *ent ATTRIBUTE_UNUSED) |
fee0225a | 150 | { |
a734f2a3 | 151 | struct unw_ia64_callback_data data; |
fee0225a | 152 | |
a734f2a3 JJ |
153 | data.pc = (Elf64_Addr) pc; |
154 | data.segment_base = segment_base; | |
155 | data.gp = gp; | |
156 | data.ret = NULL; | |
fee0225a | 157 | |
a734f2a3 JJ |
158 | if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0) |
159 | return NULL; | |
fee0225a | 160 | |
a734f2a3 | 161 | return data.ret; |
fee0225a | 162 | } |
cef03728 | 163 | #endif |