1 /* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009, 2010
2 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
27 segment and dl_iterate_phdr to avoid register/deregister calls at
37 #include <elf.h> /* Get DT_CONFIG. */
39 #include "coretypes.h"
43 #define NO_BASE_OF_ENCODED_VALUE
44 #include "unwind-pe.h"
45 #include "unwind-dw2-fde.h"
46 #include "unwind-compat.h"
49 #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
50 && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
51 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
52 # define USE_PT_GNU_EH_FRAME
55 #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
56 && defined(__FreeBSD__) && __FreeBSD__ >= 7
58 # define USE_PT_GNU_EH_FRAME
61 #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
62 && defined(TARGET_DL_ITERATE_PHDR) \
63 && defined(__sun__) && defined(__svr4__)
64 # define USE_PT_GNU_EH_FRAME
67 #if defined(USE_PT_GNU_EH_FRAME)
71 #ifndef __RELOC_POINTER
72 # define __RELOC_POINTER(ptr, base) ((ptr) + (base))
75 static const fde
* _Unwind_Find_registered_FDE (void *pc
, struct dwarf_eh_bases
*bases
);
77 #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
78 #include "unwind-dw2-fde.c"
79 #undef _Unwind_Find_FDE
81 #ifndef PT_GNU_EH_FRAME
82 #define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
85 struct unw_eh_callback_data
95 struct unw_eh_frame_hdr
97 unsigned char version
;
98 unsigned char eh_frame_ptr_enc
;
99 unsigned char fde_count_enc
;
100 unsigned char table_enc
;
103 #define FRAME_HDR_CACHE_SIZE 8
105 static struct frame_hdr_cache_element
109 _Unwind_Ptr load_base
;
110 const ElfW(Phdr
) *p_eh_frame_hdr
;
111 const ElfW(Phdr
) *p_dynamic
;
112 struct frame_hdr_cache_element
*link
;
113 } frame_hdr_cache
[FRAME_HDR_CACHE_SIZE
];
115 static struct frame_hdr_cache_element
*frame_hdr_cache_head
;
117 /* Like base_of_encoded_value, but take the base from a struct
118 unw_eh_callback_data instead of an _Unwind_Context. */
121 base_from_cb_data (unsigned char encoding
, struct unw_eh_callback_data
*data
)
123 if (encoding
== DW_EH_PE_omit
)
126 switch (encoding
& 0x70)
128 case DW_EH_PE_absptr
:
130 case DW_EH_PE_aligned
:
133 case DW_EH_PE_textrel
:
134 return (_Unwind_Ptr
) data
->tbase
;
135 case DW_EH_PE_datarel
:
136 return (_Unwind_Ptr
) data
->dbase
;
143 _Unwind_IteratePhdrCallback (struct dl_phdr_info
*info
, size_t size
, void *ptr
)
145 struct unw_eh_callback_data
*data
= (struct unw_eh_callback_data
*) ptr
;
146 const ElfW(Phdr
) *phdr
, *p_eh_frame_hdr
, *p_dynamic
;
149 struct elf32_fdpic_loadaddr load_base
;
151 _Unwind_Ptr load_base
;
153 const unsigned char *p
;
154 const struct unw_eh_frame_hdr
*hdr
;
155 _Unwind_Ptr eh_frame
;
157 _Unwind_Ptr pc_low
= 0, pc_high
= 0;
159 struct ext_dl_phdr_info
161 ElfW(Addr
) dlpi_addr
;
162 const char *dlpi_name
;
163 const ElfW(Phdr
) *dlpi_phdr
;
164 ElfW(Half
) dlpi_phnum
;
165 unsigned long long int dlpi_adds
;
166 unsigned long long int dlpi_subs
;
170 phdr
= info
->dlpi_phdr
;
171 load_base
= info
->dlpi_addr
;
172 p_eh_frame_hdr
= NULL
;
175 struct frame_hdr_cache_element
*prev_cache_entry
= NULL
,
176 *last_cache_entry
= NULL
;
178 if (data
->check_cache
&& size
>= sizeof (struct ext_dl_phdr_info
))
180 static unsigned long long adds
= -1ULL, subs
;
181 struct ext_dl_phdr_info
*einfo
= (struct ext_dl_phdr_info
*) info
;
183 /* We use a least recently used cache replacement policy. Also,
184 the most recently used cache entries are placed at the head
185 of the search chain. */
187 if (einfo
->dlpi_adds
== adds
&& einfo
->dlpi_subs
== subs
)
189 /* Find data->pc in shared library cache.
190 Set load_base, p_eh_frame_hdr and p_dynamic
191 plus match from the cache and goto
192 "Read .eh_frame_hdr header." below. */
194 struct frame_hdr_cache_element
*cache_entry
;
196 for (cache_entry
= frame_hdr_cache_head
;
198 cache_entry
= cache_entry
->link
)
200 if (data
->pc
>= cache_entry
->pc_low
201 && data
->pc
< cache_entry
->pc_high
)
203 load_base
= cache_entry
->load_base
;
204 p_eh_frame_hdr
= cache_entry
->p_eh_frame_hdr
;
205 p_dynamic
= cache_entry
->p_dynamic
;
207 /* And move the entry we're using to the head. */
208 if (cache_entry
!= frame_hdr_cache_head
)
210 prev_cache_entry
->link
= cache_entry
->link
;
211 cache_entry
->link
= frame_hdr_cache_head
;
212 frame_hdr_cache_head
= cache_entry
;
217 last_cache_entry
= cache_entry
;
218 /* Exit early if we found an unused entry. */
219 if ((cache_entry
->pc_low
| cache_entry
->pc_high
) == 0)
221 if (cache_entry
->link
!= NULL
)
222 prev_cache_entry
= cache_entry
;
227 adds
= einfo
->dlpi_adds
;
228 subs
= einfo
->dlpi_subs
;
229 /* Initialize the cache. Create a chain of cache entries,
230 with the final one terminated by a NULL link. */
232 for (i
= 0; i
< FRAME_HDR_CACHE_SIZE
; i
++)
234 frame_hdr_cache
[i
].pc_low
= 0;
235 frame_hdr_cache
[i
].pc_high
= 0;
236 frame_hdr_cache
[i
].link
= &frame_hdr_cache
[i
+1];
238 frame_hdr_cache
[i
-1].link
= NULL
;
239 frame_hdr_cache_head
= &frame_hdr_cache
[0];
240 data
->check_cache
= 0;
244 /* Make sure struct dl_phdr_info is at least as big as we need. */
245 if (size
< offsetof (struct dl_phdr_info
, dlpi_phnum
)
246 + sizeof (info
->dlpi_phnum
))
249 /* See if PC falls into one of the loaded segments. Find the eh_frame
250 segment at the same time. */
251 for (n
= info
->dlpi_phnum
; --n
>= 0; phdr
++)
253 if (phdr
->p_type
== PT_LOAD
)
255 _Unwind_Ptr vaddr
= (_Unwind_Ptr
)
256 __RELOC_POINTER (phdr
->p_vaddr
, load_base
);
257 if (data
->pc
>= vaddr
&& data
->pc
< vaddr
+ phdr
->p_memsz
)
261 pc_high
= vaddr
+ phdr
->p_memsz
;
264 else if (phdr
->p_type
== PT_GNU_EH_FRAME
)
265 p_eh_frame_hdr
= phdr
;
266 #ifdef PT_SUNW_UNWIND
267 /* Sun ld emits PT_SUNW_UNWIND .eh_frame_hdr sections instead of
268 PT_SUNW_EH_FRAME/PT_GNU_EH_FRAME, so accept them as well. */
269 else if (phdr
->p_type
== PT_SUNW_UNWIND
)
270 p_eh_frame_hdr
= phdr
;
272 else if (phdr
->p_type
== PT_DYNAMIC
)
279 if (size
>= sizeof (struct ext_dl_phdr_info
))
281 /* Move the cache entry we're about to overwrite to the head of
282 the list. If either last_cache_entry or prev_cache_entry are
283 NULL, that cache entry is already at the head. */
284 if (last_cache_entry
!= NULL
&& prev_cache_entry
!= NULL
)
286 prev_cache_entry
->link
= last_cache_entry
->link
;
287 last_cache_entry
->link
= frame_hdr_cache_head
;
288 frame_hdr_cache_head
= last_cache_entry
;
291 frame_hdr_cache_head
->load_base
= load_base
;
292 frame_hdr_cache_head
->p_eh_frame_hdr
= p_eh_frame_hdr
;
293 frame_hdr_cache_head
->p_dynamic
= p_dynamic
;
294 frame_hdr_cache_head
->pc_low
= pc_low
;
295 frame_hdr_cache_head
->pc_high
= pc_high
;
303 /* Read .eh_frame_hdr header. */
304 hdr
= (const struct unw_eh_frame_hdr
*)
305 __RELOC_POINTER (p_eh_frame_hdr
->p_vaddr
, load_base
);
306 if (hdr
->version
!= 1)
309 #ifdef CRT_GET_RFIB_DATA
314 /* For dynamically linked executables and shared libraries,
315 DT_PLTGOT is the gp value for that object. */
316 ElfW(Dyn
) *dyn
= (ElfW(Dyn
) *)
317 __RELOC_POINTER (p_dynamic
->p_vaddr
, load_base
);
318 for (; dyn
->d_tag
!= DT_NULL
; dyn
++)
319 if (dyn
->d_tag
== DT_PLTGOT
)
321 data
->dbase
= (void *) dyn
->d_un
.d_ptr
;
322 #if defined __linux__
323 /* On IA-32 Linux, _DYNAMIC is writable and GLIBC has
325 #elif defined __sun__ && defined __svr4__
326 /* On Solaris 2/x86, we need to do this ourselves. */
327 data
->dbase
+= load_base
;
332 # elif defined __FRV_FDPIC__ && defined __linux__
333 data
->dbase
= load_base
.got_value
;
334 # elif defined __x86_64__ && defined __sun__ && defined __svr4__
335 /* While CRT_GET_RFIB_DATA is also defined for 64-bit Solaris 10+/x86, it
336 doesn't apply since it uses DW_EH_PE_pcrel encoding. */
338 # error What is DW_EH_PE_datarel base on this platform?
342 p
= read_encoded_value_with_base (hdr
->eh_frame_ptr_enc
,
343 base_from_cb_data (hdr
->eh_frame_ptr_enc
,
345 (const unsigned char *) (hdr
+ 1),
348 /* We require here specific table encoding to speed things up.
349 Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
350 as base, not the processor specific DW_EH_PE_datarel. */
351 if (hdr
->fde_count_enc
!= DW_EH_PE_omit
352 && hdr
->table_enc
== (DW_EH_PE_datarel
| DW_EH_PE_sdata4
))
354 _Unwind_Ptr fde_count
;
356 p
= read_encoded_value_with_base (hdr
->fde_count_enc
,
357 base_from_cb_data (hdr
->fde_count_enc
,
360 /* Shouldn't happen. */
363 if ((((_Unwind_Ptr
) p
) & 3) == 0)
366 signed initial_loc
__attribute__ ((mode (SI
)));
367 signed fde
__attribute__ ((mode (SI
)));
369 const struct fde_table
*table
= (const struct fde_table
*) p
;
371 _Unwind_Ptr data_base
= (_Unwind_Ptr
) hdr
;
373 unsigned int f_enc
, f_enc_size
;
377 if (data
->pc
< table
[0].initial_loc
+ data_base
)
379 else if (data
->pc
< table
[mid
].initial_loc
+ data_base
)
387 if (data
->pc
< table
[mid
].initial_loc
+ data_base
)
389 else if (data
->pc
>= table
[mid
+ 1].initial_loc
+ data_base
)
395 gcc_assert (lo
< hi
);
398 f
= (fde
*) (table
[mid
].fde
+ data_base
);
399 f_enc
= get_fde_encoding (f
);
400 f_enc_size
= size_of_encoded_value (f_enc
);
401 read_encoded_value_with_base (f_enc
& 0x0f, 0,
402 &f
->pc_begin
[f_enc_size
], &range
);
403 if (data
->pc
< table
[mid
].initial_loc
+ data_base
+ range
)
405 data
->func
= (void *) (table
[mid
].initial_loc
+ data_base
);
410 /* We have no sorted search table, so need to go the slow way.
411 As soon as GLIBC will provide API so to notify that a library has been
412 removed, we could cache this (and thus use search_object). */
414 ob
.tbase
= data
->tbase
;
415 ob
.dbase
= data
->dbase
;
416 ob
.u
.single
= (fde
*) eh_frame
;
418 ob
.s
.b
.mixed_encoding
= 1; /* Need to assume worst case. */
419 data
->ret
= linear_search_fdes (&ob
, (fde
*) eh_frame
, (void *) data
->pc
);
420 if (data
->ret
!= NULL
)
423 unsigned int encoding
= get_fde_encoding (data
->ret
);
425 read_encoded_value_with_base (encoding
,
426 base_from_cb_data (encoding
, data
),
427 data
->ret
->pc_begin
, &func
);
428 data
->func
= (void *) func
;
434 _Unwind_Find_FDE (void *pc
, struct dwarf_eh_bases
*bases
)
436 struct unw_eh_callback_data data
;
439 ret
= _Unwind_Find_registered_FDE (pc
, bases
);
443 data
.pc
= (_Unwind_Ptr
) pc
;
448 data
.check_cache
= 1;
450 if (dl_iterate_phdr (_Unwind_IteratePhdrCallback
, &data
) < 0)
455 bases
->tbase
= data
.tbase
;
456 bases
->dbase
= data
.dbase
;
457 bases
->func
= data
.func
;
463 /* Prevent multiple include of header files. */
464 #define _Unwind_Find_FDE _Unwind_Find_FDE
465 #include "unwind-dw2-fde.c"
468 #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
469 alias (_Unwind_Find_FDE
);