1*2f055536Smrg /* Copyright (C) 2001-2020 Free Software Foundation, Inc.
2af526226Smrg    Contributed by Jakub Jelinek <jakub@redhat.com>.
3af526226Smrg 
4af526226Smrg    This file is part of GCC.
5af526226Smrg 
6af526226Smrg    GCC is free software; you can redistribute it and/or modify
7af526226Smrg    it under the terms of the GNU General Public License as published by
8af526226Smrg    the Free Software Foundation; either version 3, or (at your option)
9af526226Smrg    any later version.
10af526226Smrg 
11af526226Smrg    GCC is distributed in the hope that it will be useful,
12af526226Smrg    but WITHOUT ANY WARRANTY; without even the implied warranty of
13af526226Smrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14af526226Smrg    GNU General Public License for more details.
15af526226Smrg 
16af526226Smrg    Under Section 7 of GPL version 3, you are granted additional
17af526226Smrg    permissions described in the GCC Runtime Library Exception, version
18af526226Smrg    3.1, as published by the Free Software Foundation.
19af526226Smrg 
20af526226Smrg    You should have received a copy of the GNU General Public License and
21af526226Smrg    a copy of the GCC Runtime Library Exception along with this program;
22af526226Smrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23af526226Smrg    <http://www.gnu.org/licenses/>.  */
24af526226Smrg 
25af526226Smrg /* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
26af526226Smrg    segment and dl_iterate_phdr to avoid register/deregister calls at
27af526226Smrg    DSO load/unload.  */
28af526226Smrg 
29af526226Smrg #ifndef _GNU_SOURCE
30af526226Smrg #define _GNU_SOURCE 1
31af526226Smrg #endif
32af526226Smrg 
33af526226Smrg #include "tconfig.h"
34af526226Smrg #include "tsystem.h"
352b1b424dSmrg #if !defined(inhibit_libc) && defined(__GLIBC__)
36af526226Smrg #include <elf.h>		/* Get DT_CONFIG.  */
37af526226Smrg #endif
38af526226Smrg #include "coretypes.h"
39af526226Smrg #include "tm.h"
40af526226Smrg #include "libgcc_tm.h"
41af526226Smrg #include "dwarf2.h"
42af526226Smrg #include "unwind.h"
43af526226Smrg #define NO_BASE_OF_ENCODED_VALUE
44af526226Smrg #include "unwind-pe.h"
45af526226Smrg #include "unwind-dw2-fde.h"
46af526226Smrg #include "unwind-compat.h"
47af526226Smrg #include "gthr.h"
48af526226Smrg 
49af526226Smrg #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
50af526226Smrg     && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
51af526226Smrg 	|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
52af526226Smrg # define USE_PT_GNU_EH_FRAME
53af526226Smrg #endif
54af526226Smrg 
55af526226Smrg #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
56af526226Smrg     && defined(__BIONIC__)
57af526226Smrg # define USE_PT_GNU_EH_FRAME
58af526226Smrg #endif
59af526226Smrg 
60af526226Smrg #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
614646d632Smrg     && defined(TARGET_DL_ITERATE_PHDR) \
62bb2a37e4Smrg     && defined(__linux__)
63bb2a37e4Smrg # define USE_PT_GNU_EH_FRAME
64bb2a37e4Smrg #endif
65bb2a37e4Smrg 
66bb2a37e4Smrg #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
67bb2a37e4Smrg     && defined(TARGET_DL_ITERATE_PHDR) \
684646d632Smrg     && (defined(__DragonFly__) || defined(__FreeBSD__))
69af526226Smrg # define ElfW __ElfN
70af526226Smrg # define USE_PT_GNU_EH_FRAME
71af526226Smrg #endif
72af526226Smrg 
73af526226Smrg #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
743bf62c3fSmrg     && (defined(__OpenBSD__) || defined(__NetBSD__))
75af526226Smrg # define ElfW(type) Elf_##type
76af526226Smrg # define USE_PT_GNU_EH_FRAME
77af526226Smrg #endif
78af526226Smrg 
79af526226Smrg #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
80af526226Smrg     && defined(TARGET_DL_ITERATE_PHDR) \
81af526226Smrg     && defined(__sun__) && defined(__svr4__)
82af526226Smrg # define USE_PT_GNU_EH_FRAME
83af526226Smrg #endif
84af526226Smrg 
85af526226Smrg #if defined(USE_PT_GNU_EH_FRAME)
86af526226Smrg 
87af526226Smrg #include <link.h>
88af526226Smrg 
89af526226Smrg #ifndef __RELOC_POINTER
90af526226Smrg # define __RELOC_POINTER(ptr, base) ((ptr) + (base))
91af526226Smrg #endif
92af526226Smrg 
93af526226Smrg static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases);
94af526226Smrg 
95af526226Smrg #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
96af526226Smrg #include "unwind-dw2-fde.c"
97af526226Smrg #undef _Unwind_Find_FDE
98af526226Smrg 
99af526226Smrg #ifndef PT_GNU_EH_FRAME
100af526226Smrg #define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
101af526226Smrg #endif
102af526226Smrg 
103af526226Smrg struct unw_eh_callback_data
104af526226Smrg {
105af526226Smrg   _Unwind_Ptr pc;
106af526226Smrg   void *tbase;
107af526226Smrg   void *dbase;
108af526226Smrg   void *func;
109af526226Smrg   const fde *ret;
110af526226Smrg   int check_cache;
111af526226Smrg };
112af526226Smrg 
113af526226Smrg struct unw_eh_frame_hdr
114af526226Smrg {
115af526226Smrg   unsigned char version;
116af526226Smrg   unsigned char eh_frame_ptr_enc;
117af526226Smrg   unsigned char fde_count_enc;
118af526226Smrg   unsigned char table_enc;
119af526226Smrg };
120af526226Smrg 
121af526226Smrg #define FRAME_HDR_CACHE_SIZE 8
122af526226Smrg 
123af526226Smrg static struct frame_hdr_cache_element
124af526226Smrg {
125af526226Smrg   _Unwind_Ptr pc_low;
126af526226Smrg   _Unwind_Ptr pc_high;
1273bf62c3fSmrg #if defined __FRV_FDPIC__ || defined __BFIN_FDPIC__
1283bf62c3fSmrg   struct elf32_fdpic_loadaddr load_base;
1293bf62c3fSmrg #else
130af526226Smrg   _Unwind_Ptr load_base;
1313bf62c3fSmrg #endif
132af526226Smrg   const ElfW(Phdr) *p_eh_frame_hdr;
133af526226Smrg   const ElfW(Phdr) *p_dynamic;
134af526226Smrg   struct frame_hdr_cache_element *link;
135af526226Smrg } frame_hdr_cache[FRAME_HDR_CACHE_SIZE];
136af526226Smrg 
137af526226Smrg static struct frame_hdr_cache_element *frame_hdr_cache_head;
138af526226Smrg 
139af526226Smrg /* Like base_of_encoded_value, but take the base from a struct
140af526226Smrg    unw_eh_callback_data instead of an _Unwind_Context.  */
141af526226Smrg 
142af526226Smrg static _Unwind_Ptr
base_from_cb_data(unsigned char encoding,struct unw_eh_callback_data * data)143af526226Smrg base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
144af526226Smrg {
145af526226Smrg   if (encoding == DW_EH_PE_omit)
146af526226Smrg     return 0;
147af526226Smrg 
148af526226Smrg   switch (encoding & 0x70)
149af526226Smrg     {
150af526226Smrg     case DW_EH_PE_absptr:
151af526226Smrg     case DW_EH_PE_pcrel:
152af526226Smrg     case DW_EH_PE_aligned:
153af526226Smrg       return 0;
154af526226Smrg 
155af526226Smrg     case DW_EH_PE_textrel:
156af526226Smrg       return (_Unwind_Ptr) data->tbase;
157af526226Smrg     case DW_EH_PE_datarel:
158af526226Smrg       return (_Unwind_Ptr) data->dbase;
159af526226Smrg     default:
160af526226Smrg       gcc_unreachable ();
161af526226Smrg     }
162af526226Smrg }
163af526226Smrg 
164af526226Smrg static int
_Unwind_IteratePhdrCallback(struct dl_phdr_info * info,size_t size,void * ptr)165af526226Smrg _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
166af526226Smrg {
167af526226Smrg   struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
168af526226Smrg   const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
169af526226Smrg   long n, match;
1703bf62c3fSmrg #if defined __FRV_FDPIC__ || defined __BFIN_FDPIC__
171af526226Smrg   struct elf32_fdpic_loadaddr load_base;
172af526226Smrg #else
173af526226Smrg   _Unwind_Ptr load_base;
174af526226Smrg #endif
175af526226Smrg   const unsigned char *p;
176af526226Smrg   const struct unw_eh_frame_hdr *hdr;
177af526226Smrg   _Unwind_Ptr eh_frame;
178af526226Smrg   struct object ob;
179af526226Smrg   _Unwind_Ptr pc_low = 0, pc_high = 0;
180af526226Smrg 
181af526226Smrg   struct ext_dl_phdr_info
182af526226Smrg     {
183af526226Smrg       ElfW(Addr) dlpi_addr;
184af526226Smrg       const char *dlpi_name;
185af526226Smrg       const ElfW(Phdr) *dlpi_phdr;
186af526226Smrg       ElfW(Half) dlpi_phnum;
187af526226Smrg       unsigned long long int dlpi_adds;
188af526226Smrg       unsigned long long int dlpi_subs;
189af526226Smrg     };
190af526226Smrg 
191af526226Smrg   match = 0;
192af526226Smrg   phdr = info->dlpi_phdr;
193af526226Smrg   load_base = info->dlpi_addr;
194af526226Smrg   p_eh_frame_hdr = NULL;
195af526226Smrg   p_dynamic = NULL;
196af526226Smrg 
197af526226Smrg   struct frame_hdr_cache_element *prev_cache_entry = NULL,
198af526226Smrg     *last_cache_entry = NULL;
199af526226Smrg 
200af526226Smrg   if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info))
201af526226Smrg     {
202af526226Smrg       static unsigned long long adds = -1ULL, subs;
203af526226Smrg       struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info;
204af526226Smrg 
205af526226Smrg       /* We use a least recently used cache replacement policy.  Also,
206af526226Smrg 	 the most recently used cache entries are placed at the head
207af526226Smrg 	 of the search chain.  */
208af526226Smrg 
209af526226Smrg       if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs)
210af526226Smrg 	{
211af526226Smrg 	  /* Find data->pc in shared library cache.
212af526226Smrg 	     Set load_base, p_eh_frame_hdr and p_dynamic
213af526226Smrg 	     plus match from the cache and goto
214af526226Smrg 	     "Read .eh_frame_hdr header." below.  */
215af526226Smrg 
216af526226Smrg 	  struct frame_hdr_cache_element *cache_entry;
217af526226Smrg 
218af526226Smrg 	  for (cache_entry = frame_hdr_cache_head;
219af526226Smrg 	       cache_entry;
220af526226Smrg 	       cache_entry = cache_entry->link)
221af526226Smrg 	    {
222af526226Smrg 	      if (data->pc >= cache_entry->pc_low
223af526226Smrg 		  && data->pc < cache_entry->pc_high)
224af526226Smrg 		{
225af526226Smrg 		  load_base = cache_entry->load_base;
226af526226Smrg 		  p_eh_frame_hdr = cache_entry->p_eh_frame_hdr;
227af526226Smrg 		  p_dynamic = cache_entry->p_dynamic;
228af526226Smrg 
229af526226Smrg 		  /* And move the entry we're using to the head.  */
230af526226Smrg 		  if (cache_entry != frame_hdr_cache_head)
231af526226Smrg 		    {
232af526226Smrg 		      prev_cache_entry->link = cache_entry->link;
233af526226Smrg 		      cache_entry->link = frame_hdr_cache_head;
234af526226Smrg 		      frame_hdr_cache_head = cache_entry;
235af526226Smrg 		    }
236af526226Smrg 		  goto found;
237af526226Smrg 		}
238af526226Smrg 
239af526226Smrg 	      last_cache_entry = cache_entry;
240af526226Smrg 	      /* Exit early if we found an unused entry.  */
241af526226Smrg 	      if ((cache_entry->pc_low | cache_entry->pc_high) == 0)
242af526226Smrg 		break;
243af526226Smrg 	      if (cache_entry->link != NULL)
244af526226Smrg 		prev_cache_entry = cache_entry;
245af526226Smrg 	    }
246af526226Smrg 	}
247af526226Smrg       else
248af526226Smrg 	{
249af526226Smrg 	  adds = einfo->dlpi_adds;
250af526226Smrg 	  subs = einfo->dlpi_subs;
251af526226Smrg 	  /* Initialize the cache.  Create a chain of cache entries,
252af526226Smrg 	     with the final one terminated by a NULL link.  */
253af526226Smrg 	  int i;
254af526226Smrg 	  for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++)
255af526226Smrg 	    {
256af526226Smrg 	      frame_hdr_cache[i].pc_low = 0;
257af526226Smrg 	      frame_hdr_cache[i].pc_high = 0;
258af526226Smrg 	      frame_hdr_cache[i].link = &frame_hdr_cache[i+1];
259af526226Smrg 	    }
260af526226Smrg 	  frame_hdr_cache[i-1].link = NULL;
261af526226Smrg 	  frame_hdr_cache_head = &frame_hdr_cache[0];
262af526226Smrg 	  data->check_cache = 0;
263af526226Smrg 	}
264af526226Smrg     }
265af526226Smrg 
266af526226Smrg   /* Make sure struct dl_phdr_info is at least as big as we need.  */
267af526226Smrg   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
268af526226Smrg 	     + sizeof (info->dlpi_phnum))
269af526226Smrg     return -1;
270af526226Smrg 
271af526226Smrg   /* See if PC falls into one of the loaded segments.  Find the eh_frame
272af526226Smrg      segment at the same time.  */
273af526226Smrg   for (n = info->dlpi_phnum; --n >= 0; phdr++)
274af526226Smrg     {
275af526226Smrg       if (phdr->p_type == PT_LOAD)
276af526226Smrg 	{
277af526226Smrg 	  _Unwind_Ptr vaddr = (_Unwind_Ptr)
278af526226Smrg 	    __RELOC_POINTER (phdr->p_vaddr, load_base);
279af526226Smrg 	  if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
280af526226Smrg 	    {
281af526226Smrg 	      match = 1;
282af526226Smrg 	      pc_low = vaddr;
283af526226Smrg 	      pc_high =  vaddr + phdr->p_memsz;
284af526226Smrg 	    }
285af526226Smrg 	}
286af526226Smrg       else if (phdr->p_type == PT_GNU_EH_FRAME)
287af526226Smrg 	p_eh_frame_hdr = phdr;
288af526226Smrg #ifdef PT_SUNW_UNWIND
289af526226Smrg       /* Sun ld emits PT_SUNW_UNWIND .eh_frame_hdr sections instead of
290af526226Smrg 	 PT_SUNW_EH_FRAME/PT_GNU_EH_FRAME, so accept them as well.  */
291af526226Smrg       else if (phdr->p_type == PT_SUNW_UNWIND)
292af526226Smrg 	p_eh_frame_hdr = phdr;
293af526226Smrg #endif
294af526226Smrg       else if (phdr->p_type == PT_DYNAMIC)
295af526226Smrg 	p_dynamic = phdr;
296af526226Smrg     }
297af526226Smrg 
298af526226Smrg   if (!match)
299af526226Smrg     return 0;
300af526226Smrg 
301af526226Smrg   if (size >= sizeof (struct ext_dl_phdr_info))
302af526226Smrg     {
303af526226Smrg       /* Move the cache entry we're about to overwrite to the head of
304af526226Smrg 	 the list.  If either last_cache_entry or prev_cache_entry are
305af526226Smrg 	 NULL, that cache entry is already at the head.  */
306af526226Smrg       if (last_cache_entry != NULL && prev_cache_entry != NULL)
307af526226Smrg 	{
308af526226Smrg 	  prev_cache_entry->link = last_cache_entry->link;
309af526226Smrg 	  last_cache_entry->link = frame_hdr_cache_head;
310af526226Smrg 	  frame_hdr_cache_head = last_cache_entry;
311af526226Smrg 	}
312af526226Smrg 
313af526226Smrg       frame_hdr_cache_head->load_base = load_base;
314af526226Smrg       frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr;
315af526226Smrg       frame_hdr_cache_head->p_dynamic = p_dynamic;
316af526226Smrg       frame_hdr_cache_head->pc_low = pc_low;
317af526226Smrg       frame_hdr_cache_head->pc_high = pc_high;
318af526226Smrg     }
319af526226Smrg 
320af526226Smrg  found:
321af526226Smrg 
322af526226Smrg   if (!p_eh_frame_hdr)
323af526226Smrg     return 0;
324af526226Smrg 
325af526226Smrg   /* Read .eh_frame_hdr header.  */
326af526226Smrg   hdr = (const struct unw_eh_frame_hdr *)
327af526226Smrg     __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
328af526226Smrg   if (hdr->version != 1)
329af526226Smrg     return 1;
330af526226Smrg 
331af526226Smrg #ifdef CRT_GET_RFIB_DATA
332*2f055536Smrg # if defined __i386__ || defined __nios2__
333af526226Smrg   data->dbase = NULL;
334af526226Smrg   if (p_dynamic)
335af526226Smrg     {
336af526226Smrg       /* For dynamically linked executables and shared libraries,
337af526226Smrg 	 DT_PLTGOT is the gp value for that object.  */
338af526226Smrg       ElfW(Dyn) *dyn = (ElfW(Dyn) *)
339af526226Smrg 	__RELOC_POINTER (p_dynamic->p_vaddr, load_base);
340af526226Smrg       for (; dyn->d_tag != DT_NULL ; dyn++)
341af526226Smrg 	if (dyn->d_tag == DT_PLTGOT)
342af526226Smrg 	  {
343af526226Smrg 	    data->dbase = (void *) dyn->d_un.d_ptr;
344af526226Smrg #if defined __linux__
345af526226Smrg 	    /* On IA-32 Linux, _DYNAMIC is writable and GLIBC has
346af526226Smrg 	       relocated it.  */
347af526226Smrg #elif defined __sun__ && defined __svr4__
348af526226Smrg 	    /* On Solaris 2/x86, we need to do this ourselves.  */
349af526226Smrg 	    data->dbase += load_base;
350af526226Smrg #endif
351af526226Smrg 	    break;
352af526226Smrg 	  }
353af526226Smrg     }
3543bf62c3fSmrg # elif (defined __FRV_FDPIC__ || defined __BFIN_FDPIC__) && defined __linux__
355af526226Smrg   data->dbase = load_base.got_value;
356af526226Smrg # else
357af526226Smrg #  error What is DW_EH_PE_datarel base on this platform?
358af526226Smrg # endif
359af526226Smrg #endif
360af526226Smrg 
361af526226Smrg   p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
362af526226Smrg 				    base_from_cb_data (hdr->eh_frame_ptr_enc,
363af526226Smrg 						       data),
364af526226Smrg 				    (const unsigned char *) (hdr + 1),
365af526226Smrg 				    &eh_frame);
366af526226Smrg 
367af526226Smrg   /* We require here specific table encoding to speed things up.
368af526226Smrg      Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
369af526226Smrg      as base, not the processor specific DW_EH_PE_datarel.  */
370af526226Smrg   if (hdr->fde_count_enc != DW_EH_PE_omit
371af526226Smrg       && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
372af526226Smrg     {
373af526226Smrg       _Unwind_Ptr fde_count;
374af526226Smrg 
375af526226Smrg       p = read_encoded_value_with_base (hdr->fde_count_enc,
376af526226Smrg 					base_from_cb_data (hdr->fde_count_enc,
377af526226Smrg 							   data),
378af526226Smrg 					p, &fde_count);
379af526226Smrg       /* Shouldn't happen.  */
380af526226Smrg       if (fde_count == 0)
381af526226Smrg 	return 1;
382af526226Smrg       if ((((_Unwind_Ptr) p) & 3) == 0)
383af526226Smrg 	{
384af526226Smrg 	  struct fde_table {
385af526226Smrg 	    signed initial_loc __attribute__ ((mode (SI)));
386af526226Smrg 	    signed fde __attribute__ ((mode (SI)));
387af526226Smrg 	  };
388af526226Smrg 	  const struct fde_table *table = (const struct fde_table *) p;
389af526226Smrg 	  size_t lo, hi, mid;
390af526226Smrg 	  _Unwind_Ptr data_base = (_Unwind_Ptr) hdr;
391af526226Smrg 	  fde *f;
392af526226Smrg 	  unsigned int f_enc, f_enc_size;
393af526226Smrg 	  _Unwind_Ptr range;
394af526226Smrg 
395af526226Smrg 	  mid = fde_count - 1;
396af526226Smrg 	  if (data->pc < table[0].initial_loc + data_base)
397af526226Smrg 	    return 1;
398af526226Smrg 	  else if (data->pc < table[mid].initial_loc + data_base)
399af526226Smrg 	    {
400af526226Smrg 	      lo = 0;
401af526226Smrg 	      hi = mid;
402af526226Smrg 
403af526226Smrg 	      while (lo < hi)
404af526226Smrg 		{
405af526226Smrg 		  mid = (lo + hi) / 2;
406af526226Smrg 		  if (data->pc < table[mid].initial_loc + data_base)
407af526226Smrg 		    hi = mid;
408af526226Smrg 		  else if (data->pc >= table[mid + 1].initial_loc + data_base)
409af526226Smrg 		    lo = mid + 1;
410af526226Smrg 		  else
411af526226Smrg 		    break;
412af526226Smrg 		}
413af526226Smrg 
414af526226Smrg 	      gcc_assert (lo < hi);
415af526226Smrg 	    }
416af526226Smrg 
417af526226Smrg 	  f = (fde *) (table[mid].fde + data_base);
418af526226Smrg 	  f_enc = get_fde_encoding (f);
419af526226Smrg 	  f_enc_size = size_of_encoded_value (f_enc);
420af526226Smrg 	  read_encoded_value_with_base (f_enc & 0x0f, 0,
421af526226Smrg 					&f->pc_begin[f_enc_size], &range);
422af526226Smrg 	  if (data->pc < table[mid].initial_loc + data_base + range)
423af526226Smrg 	    data->ret = f;
424af526226Smrg 	  data->func = (void *) (table[mid].initial_loc + data_base);
425af526226Smrg 	  return 1;
426af526226Smrg 	}
427af526226Smrg     }
428af526226Smrg 
429af526226Smrg   /* We have no sorted search table, so need to go the slow way.
430af526226Smrg      As soon as GLIBC will provide API so to notify that a library has been
431af526226Smrg      removed, we could cache this (and thus use search_object).  */
432af526226Smrg   ob.pc_begin = NULL;
433af526226Smrg   ob.tbase = data->tbase;
434af526226Smrg   ob.dbase = data->dbase;
435af526226Smrg   ob.u.single = (fde *) eh_frame;
436af526226Smrg   ob.s.i = 0;
437af526226Smrg   ob.s.b.mixed_encoding = 1;  /* Need to assume worst case.  */
438af526226Smrg   data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc);
439af526226Smrg   if (data->ret != NULL)
440af526226Smrg     {
441af526226Smrg       _Unwind_Ptr func;
442af526226Smrg       unsigned int encoding = get_fde_encoding (data->ret);
443af526226Smrg 
444af526226Smrg       read_encoded_value_with_base (encoding,
445af526226Smrg 				    base_from_cb_data (encoding, data),
446af526226Smrg 				    data->ret->pc_begin, &func);
447af526226Smrg       data->func = (void *) func;
448af526226Smrg     }
449af526226Smrg   return 1;
450af526226Smrg }
451af526226Smrg 
452af526226Smrg const fde *
_Unwind_Find_FDE(void * pc,struct dwarf_eh_bases * bases)453af526226Smrg _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
454af526226Smrg {
455af526226Smrg   struct unw_eh_callback_data data;
456af526226Smrg   const fde *ret;
457af526226Smrg 
458af526226Smrg   ret = _Unwind_Find_registered_FDE (pc, bases);
459af526226Smrg   if (ret != NULL)
460af526226Smrg     return ret;
461af526226Smrg 
462af526226Smrg   data.pc = (_Unwind_Ptr) pc;
463af526226Smrg   data.tbase = NULL;
464af526226Smrg   data.dbase = NULL;
465af526226Smrg   data.func = NULL;
466af526226Smrg   data.ret = NULL;
467af526226Smrg   data.check_cache = 1;
468af526226Smrg 
469af526226Smrg   if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
470af526226Smrg     return NULL;
471af526226Smrg 
472af526226Smrg   if (data.ret)
473af526226Smrg     {
474af526226Smrg       bases->tbase = data.tbase;
475af526226Smrg       bases->dbase = data.dbase;
476af526226Smrg       bases->func = data.func;
477af526226Smrg     }
478af526226Smrg   return data.ret;
479af526226Smrg }
480af526226Smrg 
481af526226Smrg #else
482af526226Smrg /* Prevent multiple include of header files.  */
483af526226Smrg #define _Unwind_Find_FDE _Unwind_Find_FDE
484af526226Smrg #include "unwind-dw2-fde.c"
485af526226Smrg #endif
486af526226Smrg 
487af526226Smrg #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
488af526226Smrg alias (_Unwind_Find_FDE);
489af526226Smrg #endif
490