138fd1498Szrj /* Copyright (C) 2001-2018 Free Software Foundation, Inc.
238fd1498Szrj    Contributed by Jakub Jelinek <jakub@redhat.com>.
338fd1498Szrj 
438fd1498Szrj    This file is part of GCC.
538fd1498Szrj 
638fd1498Szrj    GCC is free software; you can redistribute it and/or modify
738fd1498Szrj    it under the terms of the GNU General Public License as published by
838fd1498Szrj    the Free Software Foundation; either version 3, or (at your option)
938fd1498Szrj    any later version.
1038fd1498Szrj 
1138fd1498Szrj    GCC is distributed in the hope that it will be useful,
1238fd1498Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
1338fd1498Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1438fd1498Szrj    GNU General Public License for more details.
1538fd1498Szrj 
1638fd1498Szrj    Under Section 7 of GPL version 3, you are granted additional
1738fd1498Szrj    permissions described in the GCC Runtime Library Exception, version
1838fd1498Szrj    3.1, as published by the Free Software Foundation.
1938fd1498Szrj 
2038fd1498Szrj    You should have received a copy of the GNU General Public License and
2138fd1498Szrj    a copy of the GCC Runtime Library Exception along with this program;
2238fd1498Szrj    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2338fd1498Szrj    <http://www.gnu.org/licenses/>.  */
2438fd1498Szrj 
2538fd1498Szrj /* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
2638fd1498Szrj    segment and dl_iterate_phdr to avoid register/deregister calls at
2738fd1498Szrj    DSO load/unload.  */
2838fd1498Szrj 
2938fd1498Szrj #ifndef _GNU_SOURCE
3038fd1498Szrj #define _GNU_SOURCE 1
3138fd1498Szrj #endif
3238fd1498Szrj 
3338fd1498Szrj #include "tconfig.h"
3438fd1498Szrj #include "tsystem.h"
3538fd1498Szrj #if !defined(inhibit_libc) && !defined(__OpenBSD__)
3638fd1498Szrj #include <elf.h>		/* Get DT_CONFIG.  */
3738fd1498Szrj #endif
3838fd1498Szrj #include "coretypes.h"
3938fd1498Szrj #include "tm.h"
4038fd1498Szrj #include "libgcc_tm.h"
4138fd1498Szrj #include "dwarf2.h"
4238fd1498Szrj #include "unwind.h"
4338fd1498Szrj #define NO_BASE_OF_ENCODED_VALUE
4438fd1498Szrj #include "unwind-pe.h"
4538fd1498Szrj #include "unwind-dw2-fde.h"
4638fd1498Szrj #include "unwind-compat.h"
4738fd1498Szrj #include "gthr.h"
4838fd1498Szrj 
4938fd1498Szrj #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
5038fd1498Szrj     && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
5138fd1498Szrj 	|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
5238fd1498Szrj # define USE_PT_GNU_EH_FRAME
5338fd1498Szrj #endif
5438fd1498Szrj 
5538fd1498Szrj #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
5638fd1498Szrj     && defined(__BIONIC__)
5738fd1498Szrj # define USE_PT_GNU_EH_FRAME
5838fd1498Szrj #endif
5938fd1498Szrj 
6038fd1498Szrj #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
6138fd1498Szrj     && defined(TARGET_DL_ITERATE_PHDR) \
6238fd1498Szrj     && defined(__linux__)
6338fd1498Szrj # define USE_PT_GNU_EH_FRAME
6438fd1498Szrj #endif
6538fd1498Szrj 
6638fd1498Szrj #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
6738fd1498Szrj     && defined(TARGET_DL_ITERATE_PHDR) \
682007c584SSascha Wildner     && (defined(__DragonFly__) || defined(__FreeBSD__))
69*fca8e87bSSascha Wildner #ifndef ElfW
7038fd1498Szrj # define ElfW __ElfN
719cf0c62dSSascha Wildner #endif
7238fd1498Szrj # define USE_PT_GNU_EH_FRAME
7338fd1498Szrj #endif
7438fd1498Szrj 
7538fd1498Szrj #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
7638fd1498Szrj     && (defined(__OpenBSD__) || defined(__NetBSD__))
7738fd1498Szrj # define ElfW(type) Elf_##type
7838fd1498Szrj # define USE_PT_GNU_EH_FRAME
7938fd1498Szrj #endif
8038fd1498Szrj 
8138fd1498Szrj #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
8238fd1498Szrj     && defined(TARGET_DL_ITERATE_PHDR) \
8338fd1498Szrj     && defined(__sun__) && defined(__svr4__)
8438fd1498Szrj # define USE_PT_GNU_EH_FRAME
8538fd1498Szrj #endif
8638fd1498Szrj 
8738fd1498Szrj #if defined(USE_PT_GNU_EH_FRAME)
8838fd1498Szrj 
8938fd1498Szrj #include <link.h>
9038fd1498Szrj 
9138fd1498Szrj #ifndef __RELOC_POINTER
9238fd1498Szrj # define __RELOC_POINTER(ptr, base) ((ptr) + (base))
9338fd1498Szrj #endif
9438fd1498Szrj 
9538fd1498Szrj static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases);
9638fd1498Szrj 
9738fd1498Szrj #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
9838fd1498Szrj #include "unwind-dw2-fde.c"
9938fd1498Szrj #undef _Unwind_Find_FDE
10038fd1498Szrj 
10138fd1498Szrj #ifndef PT_GNU_EH_FRAME
10238fd1498Szrj #define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
10338fd1498Szrj #endif
10438fd1498Szrj 
10538fd1498Szrj struct unw_eh_callback_data
10638fd1498Szrj {
10738fd1498Szrj   _Unwind_Ptr pc;
10838fd1498Szrj   void *tbase;
10938fd1498Szrj   void *dbase;
11038fd1498Szrj   void *func;
11138fd1498Szrj   const fde *ret;
11238fd1498Szrj   int check_cache;
11338fd1498Szrj };
11438fd1498Szrj 
11538fd1498Szrj struct unw_eh_frame_hdr
11638fd1498Szrj {
11738fd1498Szrj   unsigned char version;
11838fd1498Szrj   unsigned char eh_frame_ptr_enc;
11938fd1498Szrj   unsigned char fde_count_enc;
12038fd1498Szrj   unsigned char table_enc;
12138fd1498Szrj };
12238fd1498Szrj 
12338fd1498Szrj #define FRAME_HDR_CACHE_SIZE 8
12438fd1498Szrj 
12538fd1498Szrj static struct frame_hdr_cache_element
12638fd1498Szrj {
12738fd1498Szrj   _Unwind_Ptr pc_low;
12838fd1498Szrj   _Unwind_Ptr pc_high;
12938fd1498Szrj #if defined __FRV_FDPIC__ || defined __BFIN_FDPIC__
13038fd1498Szrj   struct elf32_fdpic_loadaddr load_base;
13138fd1498Szrj #else
13238fd1498Szrj   _Unwind_Ptr load_base;
13338fd1498Szrj #endif
13438fd1498Szrj   const ElfW(Phdr) *p_eh_frame_hdr;
13538fd1498Szrj   const ElfW(Phdr) *p_dynamic;
13638fd1498Szrj   struct frame_hdr_cache_element *link;
13738fd1498Szrj } frame_hdr_cache[FRAME_HDR_CACHE_SIZE];
13838fd1498Szrj 
13938fd1498Szrj static struct frame_hdr_cache_element *frame_hdr_cache_head;
14038fd1498Szrj 
14138fd1498Szrj /* Like base_of_encoded_value, but take the base from a struct
14238fd1498Szrj    unw_eh_callback_data instead of an _Unwind_Context.  */
14338fd1498Szrj 
14438fd1498Szrj static _Unwind_Ptr
base_from_cb_data(unsigned char encoding,struct unw_eh_callback_data * data)14538fd1498Szrj base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
14638fd1498Szrj {
14738fd1498Szrj   if (encoding == DW_EH_PE_omit)
14838fd1498Szrj     return 0;
14938fd1498Szrj 
15038fd1498Szrj   switch (encoding & 0x70)
15138fd1498Szrj     {
15238fd1498Szrj     case DW_EH_PE_absptr:
15338fd1498Szrj     case DW_EH_PE_pcrel:
15438fd1498Szrj     case DW_EH_PE_aligned:
15538fd1498Szrj       return 0;
15638fd1498Szrj 
15738fd1498Szrj     case DW_EH_PE_textrel:
15838fd1498Szrj       return (_Unwind_Ptr) data->tbase;
15938fd1498Szrj     case DW_EH_PE_datarel:
16038fd1498Szrj       return (_Unwind_Ptr) data->dbase;
16138fd1498Szrj     default:
16238fd1498Szrj       gcc_unreachable ();
16338fd1498Szrj     }
16438fd1498Szrj }
16538fd1498Szrj 
16638fd1498Szrj static int
_Unwind_IteratePhdrCallback(struct dl_phdr_info * info,size_t size,void * ptr)16738fd1498Szrj _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
16838fd1498Szrj {
16938fd1498Szrj   struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
17038fd1498Szrj   const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
17138fd1498Szrj   long n, match;
17238fd1498Szrj #if defined __FRV_FDPIC__ || defined __BFIN_FDPIC__
17338fd1498Szrj   struct elf32_fdpic_loadaddr load_base;
17438fd1498Szrj #else
17538fd1498Szrj   _Unwind_Ptr load_base;
17638fd1498Szrj #endif
17738fd1498Szrj   const unsigned char *p;
17838fd1498Szrj   const struct unw_eh_frame_hdr *hdr;
17938fd1498Szrj   _Unwind_Ptr eh_frame;
18038fd1498Szrj   struct object ob;
18138fd1498Szrj   _Unwind_Ptr pc_low = 0, pc_high = 0;
18238fd1498Szrj 
18338fd1498Szrj   struct ext_dl_phdr_info
18438fd1498Szrj     {
18538fd1498Szrj       ElfW(Addr) dlpi_addr;
18638fd1498Szrj       const char *dlpi_name;
18738fd1498Szrj       const ElfW(Phdr) *dlpi_phdr;
18838fd1498Szrj       ElfW(Half) dlpi_phnum;
18938fd1498Szrj       unsigned long long int dlpi_adds;
19038fd1498Szrj       unsigned long long int dlpi_subs;
19138fd1498Szrj     };
19238fd1498Szrj 
19338fd1498Szrj   match = 0;
19438fd1498Szrj   phdr = info->dlpi_phdr;
19538fd1498Szrj   load_base = info->dlpi_addr;
19638fd1498Szrj   p_eh_frame_hdr = NULL;
19738fd1498Szrj   p_dynamic = NULL;
19838fd1498Szrj 
19938fd1498Szrj   struct frame_hdr_cache_element *prev_cache_entry = NULL,
20038fd1498Szrj     *last_cache_entry = NULL;
20138fd1498Szrj 
20238fd1498Szrj   if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info))
20338fd1498Szrj     {
20438fd1498Szrj       static unsigned long long adds = -1ULL, subs;
20538fd1498Szrj       struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info;
20638fd1498Szrj 
20738fd1498Szrj       /* We use a least recently used cache replacement policy.  Also,
20838fd1498Szrj 	 the most recently used cache entries are placed at the head
20938fd1498Szrj 	 of the search chain.  */
21038fd1498Szrj 
21138fd1498Szrj       if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs)
21238fd1498Szrj 	{
21338fd1498Szrj 	  /* Find data->pc in shared library cache.
21438fd1498Szrj 	     Set load_base, p_eh_frame_hdr and p_dynamic
21538fd1498Szrj 	     plus match from the cache and goto
21638fd1498Szrj 	     "Read .eh_frame_hdr header." below.  */
21738fd1498Szrj 
21838fd1498Szrj 	  struct frame_hdr_cache_element *cache_entry;
21938fd1498Szrj 
22038fd1498Szrj 	  for (cache_entry = frame_hdr_cache_head;
22138fd1498Szrj 	       cache_entry;
22238fd1498Szrj 	       cache_entry = cache_entry->link)
22338fd1498Szrj 	    {
22438fd1498Szrj 	      if (data->pc >= cache_entry->pc_low
22538fd1498Szrj 		  && data->pc < cache_entry->pc_high)
22638fd1498Szrj 		{
22738fd1498Szrj 		  load_base = cache_entry->load_base;
22838fd1498Szrj 		  p_eh_frame_hdr = cache_entry->p_eh_frame_hdr;
22938fd1498Szrj 		  p_dynamic = cache_entry->p_dynamic;
23038fd1498Szrj 
23138fd1498Szrj 		  /* And move the entry we're using to the head.  */
23238fd1498Szrj 		  if (cache_entry != frame_hdr_cache_head)
23338fd1498Szrj 		    {
23438fd1498Szrj 		      prev_cache_entry->link = cache_entry->link;
23538fd1498Szrj 		      cache_entry->link = frame_hdr_cache_head;
23638fd1498Szrj 		      frame_hdr_cache_head = cache_entry;
23738fd1498Szrj 		    }
23838fd1498Szrj 		  goto found;
23938fd1498Szrj 		}
24038fd1498Szrj 
24138fd1498Szrj 	      last_cache_entry = cache_entry;
24238fd1498Szrj 	      /* Exit early if we found an unused entry.  */
24338fd1498Szrj 	      if ((cache_entry->pc_low | cache_entry->pc_high) == 0)
24438fd1498Szrj 		break;
24538fd1498Szrj 	      if (cache_entry->link != NULL)
24638fd1498Szrj 		prev_cache_entry = cache_entry;
24738fd1498Szrj 	    }
24838fd1498Szrj 	}
24938fd1498Szrj       else
25038fd1498Szrj 	{
25138fd1498Szrj 	  adds = einfo->dlpi_adds;
25238fd1498Szrj 	  subs = einfo->dlpi_subs;
25338fd1498Szrj 	  /* Initialize the cache.  Create a chain of cache entries,
25438fd1498Szrj 	     with the final one terminated by a NULL link.  */
25538fd1498Szrj 	  int i;
25638fd1498Szrj 	  for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++)
25738fd1498Szrj 	    {
25838fd1498Szrj 	      frame_hdr_cache[i].pc_low = 0;
25938fd1498Szrj 	      frame_hdr_cache[i].pc_high = 0;
26038fd1498Szrj 	      frame_hdr_cache[i].link = &frame_hdr_cache[i+1];
26138fd1498Szrj 	    }
26238fd1498Szrj 	  frame_hdr_cache[i-1].link = NULL;
26338fd1498Szrj 	  frame_hdr_cache_head = &frame_hdr_cache[0];
26438fd1498Szrj 	  data->check_cache = 0;
26538fd1498Szrj 	}
26638fd1498Szrj     }
26738fd1498Szrj 
26838fd1498Szrj   /* Make sure struct dl_phdr_info is at least as big as we need.  */
26938fd1498Szrj   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
27038fd1498Szrj 	     + sizeof (info->dlpi_phnum))
27138fd1498Szrj     return -1;
27238fd1498Szrj 
27338fd1498Szrj   /* See if PC falls into one of the loaded segments.  Find the eh_frame
27438fd1498Szrj      segment at the same time.  */
27538fd1498Szrj   for (n = info->dlpi_phnum; --n >= 0; phdr++)
27638fd1498Szrj     {
27738fd1498Szrj       if (phdr->p_type == PT_LOAD)
27838fd1498Szrj 	{
27938fd1498Szrj 	  _Unwind_Ptr vaddr = (_Unwind_Ptr)
28038fd1498Szrj 	    __RELOC_POINTER (phdr->p_vaddr, load_base);
28138fd1498Szrj 	  if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
28238fd1498Szrj 	    {
28338fd1498Szrj 	      match = 1;
28438fd1498Szrj 	      pc_low = vaddr;
28538fd1498Szrj 	      pc_high =  vaddr + phdr->p_memsz;
28638fd1498Szrj 	    }
28738fd1498Szrj 	}
28838fd1498Szrj       else if (phdr->p_type == PT_GNU_EH_FRAME)
28938fd1498Szrj 	p_eh_frame_hdr = phdr;
29038fd1498Szrj #ifdef PT_SUNW_UNWIND
29138fd1498Szrj       /* Sun ld emits PT_SUNW_UNWIND .eh_frame_hdr sections instead of
29238fd1498Szrj 	 PT_SUNW_EH_FRAME/PT_GNU_EH_FRAME, so accept them as well.  */
29338fd1498Szrj       else if (phdr->p_type == PT_SUNW_UNWIND)
29438fd1498Szrj 	p_eh_frame_hdr = phdr;
29538fd1498Szrj #endif
29638fd1498Szrj       else if (phdr->p_type == PT_DYNAMIC)
29738fd1498Szrj 	p_dynamic = phdr;
29838fd1498Szrj     }
29938fd1498Szrj 
30038fd1498Szrj   if (!match)
30138fd1498Szrj     return 0;
30238fd1498Szrj 
30338fd1498Szrj   if (size >= sizeof (struct ext_dl_phdr_info))
30438fd1498Szrj     {
30538fd1498Szrj       /* Move the cache entry we're about to overwrite to the head of
30638fd1498Szrj 	 the list.  If either last_cache_entry or prev_cache_entry are
30738fd1498Szrj 	 NULL, that cache entry is already at the head.  */
30838fd1498Szrj       if (last_cache_entry != NULL && prev_cache_entry != NULL)
30938fd1498Szrj 	{
31038fd1498Szrj 	  prev_cache_entry->link = last_cache_entry->link;
31138fd1498Szrj 	  last_cache_entry->link = frame_hdr_cache_head;
31238fd1498Szrj 	  frame_hdr_cache_head = last_cache_entry;
31338fd1498Szrj 	}
31438fd1498Szrj 
31538fd1498Szrj       frame_hdr_cache_head->load_base = load_base;
31638fd1498Szrj       frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr;
31738fd1498Szrj       frame_hdr_cache_head->p_dynamic = p_dynamic;
31838fd1498Szrj       frame_hdr_cache_head->pc_low = pc_low;
31938fd1498Szrj       frame_hdr_cache_head->pc_high = pc_high;
32038fd1498Szrj     }
32138fd1498Szrj 
32238fd1498Szrj  found:
32338fd1498Szrj 
32438fd1498Szrj   if (!p_eh_frame_hdr)
32538fd1498Szrj     return 0;
32638fd1498Szrj 
32738fd1498Szrj   /* Read .eh_frame_hdr header.  */
32838fd1498Szrj   hdr = (const struct unw_eh_frame_hdr *)
32938fd1498Szrj     __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
33038fd1498Szrj   if (hdr->version != 1)
33138fd1498Szrj     return 1;
33238fd1498Szrj 
33338fd1498Szrj #ifdef CRT_GET_RFIB_DATA
33438fd1498Szrj # ifdef __i386__
33538fd1498Szrj   data->dbase = NULL;
33638fd1498Szrj   if (p_dynamic)
33738fd1498Szrj     {
33838fd1498Szrj       /* For dynamically linked executables and shared libraries,
33938fd1498Szrj 	 DT_PLTGOT is the gp value for that object.  */
34038fd1498Szrj       ElfW(Dyn) *dyn = (ElfW(Dyn) *)
34138fd1498Szrj 	__RELOC_POINTER (p_dynamic->p_vaddr, load_base);
34238fd1498Szrj       for (; dyn->d_tag != DT_NULL ; dyn++)
34338fd1498Szrj 	if (dyn->d_tag == DT_PLTGOT)
34438fd1498Szrj 	  {
34538fd1498Szrj 	    data->dbase = (void *) dyn->d_un.d_ptr;
34638fd1498Szrj #if defined __linux__
34738fd1498Szrj 	    /* On IA-32 Linux, _DYNAMIC is writable and GLIBC has
34838fd1498Szrj 	       relocated it.  */
34938fd1498Szrj #elif defined __sun__ && defined __svr4__
35038fd1498Szrj 	    /* On Solaris 2/x86, we need to do this ourselves.  */
35138fd1498Szrj 	    data->dbase += load_base;
35238fd1498Szrj #endif
35338fd1498Szrj 	    break;
35438fd1498Szrj 	  }
35538fd1498Szrj     }
35638fd1498Szrj # elif (defined __FRV_FDPIC__ || defined __BFIN_FDPIC__) && defined __linux__
35738fd1498Szrj   data->dbase = load_base.got_value;
35838fd1498Szrj # else
35938fd1498Szrj #  error What is DW_EH_PE_datarel base on this platform?
36038fd1498Szrj # endif
36138fd1498Szrj #endif
36238fd1498Szrj 
36338fd1498Szrj   p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
36438fd1498Szrj 				    base_from_cb_data (hdr->eh_frame_ptr_enc,
36538fd1498Szrj 						       data),
36638fd1498Szrj 				    (const unsigned char *) (hdr + 1),
36738fd1498Szrj 				    &eh_frame);
36838fd1498Szrj 
36938fd1498Szrj   /* We require here specific table encoding to speed things up.
37038fd1498Szrj      Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
37138fd1498Szrj      as base, not the processor specific DW_EH_PE_datarel.  */
37238fd1498Szrj   if (hdr->fde_count_enc != DW_EH_PE_omit
37338fd1498Szrj       && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
37438fd1498Szrj     {
37538fd1498Szrj       _Unwind_Ptr fde_count;
37638fd1498Szrj 
37738fd1498Szrj       p = read_encoded_value_with_base (hdr->fde_count_enc,
37838fd1498Szrj 					base_from_cb_data (hdr->fde_count_enc,
37938fd1498Szrj 							   data),
38038fd1498Szrj 					p, &fde_count);
38138fd1498Szrj       /* Shouldn't happen.  */
38238fd1498Szrj       if (fde_count == 0)
38338fd1498Szrj 	return 1;
38438fd1498Szrj       if ((((_Unwind_Ptr) p) & 3) == 0)
38538fd1498Szrj 	{
38638fd1498Szrj 	  struct fde_table {
38738fd1498Szrj 	    signed initial_loc __attribute__ ((mode (SI)));
38838fd1498Szrj 	    signed fde __attribute__ ((mode (SI)));
38938fd1498Szrj 	  };
39038fd1498Szrj 	  const struct fde_table *table = (const struct fde_table *) p;
39138fd1498Szrj 	  size_t lo, hi, mid;
39238fd1498Szrj 	  _Unwind_Ptr data_base = (_Unwind_Ptr) hdr;
39338fd1498Szrj 	  fde *f;
39438fd1498Szrj 	  unsigned int f_enc, f_enc_size;
39538fd1498Szrj 	  _Unwind_Ptr range;
39638fd1498Szrj 
39738fd1498Szrj 	  mid = fde_count - 1;
39838fd1498Szrj 	  if (data->pc < table[0].initial_loc + data_base)
39938fd1498Szrj 	    return 1;
40038fd1498Szrj 	  else if (data->pc < table[mid].initial_loc + data_base)
40138fd1498Szrj 	    {
40238fd1498Szrj 	      lo = 0;
40338fd1498Szrj 	      hi = mid;
40438fd1498Szrj 
40538fd1498Szrj 	      while (lo < hi)
40638fd1498Szrj 		{
40738fd1498Szrj 		  mid = (lo + hi) / 2;
40838fd1498Szrj 		  if (data->pc < table[mid].initial_loc + data_base)
40938fd1498Szrj 		    hi = mid;
41038fd1498Szrj 		  else if (data->pc >= table[mid + 1].initial_loc + data_base)
41138fd1498Szrj 		    lo = mid + 1;
41238fd1498Szrj 		  else
41338fd1498Szrj 		    break;
41438fd1498Szrj 		}
41538fd1498Szrj 
41638fd1498Szrj 	      gcc_assert (lo < hi);
41738fd1498Szrj 	    }
41838fd1498Szrj 
41938fd1498Szrj 	  f = (fde *) (table[mid].fde + data_base);
42038fd1498Szrj 	  f_enc = get_fde_encoding (f);
42138fd1498Szrj 	  f_enc_size = size_of_encoded_value (f_enc);
42238fd1498Szrj 	  read_encoded_value_with_base (f_enc & 0x0f, 0,
42338fd1498Szrj 					&f->pc_begin[f_enc_size], &range);
42438fd1498Szrj 	  if (data->pc < table[mid].initial_loc + data_base + range)
42538fd1498Szrj 	    data->ret = f;
42638fd1498Szrj 	  data->func = (void *) (table[mid].initial_loc + data_base);
42738fd1498Szrj 	  return 1;
42838fd1498Szrj 	}
42938fd1498Szrj     }
43038fd1498Szrj 
43138fd1498Szrj   /* We have no sorted search table, so need to go the slow way.
43238fd1498Szrj      As soon as GLIBC will provide API so to notify that a library has been
43338fd1498Szrj      removed, we could cache this (and thus use search_object).  */
43438fd1498Szrj   ob.pc_begin = NULL;
43538fd1498Szrj   ob.tbase = data->tbase;
43638fd1498Szrj   ob.dbase = data->dbase;
43738fd1498Szrj   ob.u.single = (fde *) eh_frame;
43838fd1498Szrj   ob.s.i = 0;
43938fd1498Szrj   ob.s.b.mixed_encoding = 1;  /* Need to assume worst case.  */
44038fd1498Szrj   data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc);
44138fd1498Szrj   if (data->ret != NULL)
44238fd1498Szrj     {
44338fd1498Szrj       _Unwind_Ptr func;
44438fd1498Szrj       unsigned int encoding = get_fde_encoding (data->ret);
44538fd1498Szrj 
44638fd1498Szrj       read_encoded_value_with_base (encoding,
44738fd1498Szrj 				    base_from_cb_data (encoding, data),
44838fd1498Szrj 				    data->ret->pc_begin, &func);
44938fd1498Szrj       data->func = (void *) func;
45038fd1498Szrj     }
45138fd1498Szrj   return 1;
45238fd1498Szrj }
45338fd1498Szrj 
45438fd1498Szrj const fde *
_Unwind_Find_FDE(void * pc,struct dwarf_eh_bases * bases)45538fd1498Szrj _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
45638fd1498Szrj {
45738fd1498Szrj   struct unw_eh_callback_data data;
45838fd1498Szrj   const fde *ret;
45938fd1498Szrj 
46038fd1498Szrj   ret = _Unwind_Find_registered_FDE (pc, bases);
46138fd1498Szrj   if (ret != NULL)
46238fd1498Szrj     return ret;
46338fd1498Szrj 
46438fd1498Szrj   data.pc = (_Unwind_Ptr) pc;
46538fd1498Szrj   data.tbase = NULL;
46638fd1498Szrj   data.dbase = NULL;
46738fd1498Szrj   data.func = NULL;
46838fd1498Szrj   data.ret = NULL;
46938fd1498Szrj   data.check_cache = 1;
47038fd1498Szrj 
47138fd1498Szrj   if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
47238fd1498Szrj     return NULL;
47338fd1498Szrj 
47438fd1498Szrj   if (data.ret)
47538fd1498Szrj     {
47638fd1498Szrj       bases->tbase = data.tbase;
47738fd1498Szrj       bases->dbase = data.dbase;
47838fd1498Szrj       bases->func = data.func;
47938fd1498Szrj     }
48038fd1498Szrj   return data.ret;
48138fd1498Szrj }
48238fd1498Szrj 
48338fd1498Szrj #else
48438fd1498Szrj /* Prevent multiple include of header files.  */
48538fd1498Szrj #define _Unwind_Find_FDE _Unwind_Find_FDE
48638fd1498Szrj #include "unwind-dw2-fde.c"
48738fd1498Szrj #endif
48838fd1498Szrj 
48938fd1498Szrj #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
49038fd1498Szrj alias (_Unwind_Find_FDE);
49138fd1498Szrj #endif
492