(root)/
gcc-13.2.0/
libgcc/
unwind-dw2-fde-dip.c
       1  /* Copyright (C) 2001-2023 Free Software Foundation, Inc.
       2     Contributed by Jakub Jelinek <jakub@redhat.com>.
       3  
       4     This file is part of GCC.
       5  
       6     GCC is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     GCC is distributed in the hope that it will be useful,
      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  
      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/>.  */
      24  
      25  /* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
      26     segment and dl_iterate_phdr to avoid register/deregister calls at
      27     DSO load/unload.  */
      28  
      29  #ifndef _GNU_SOURCE
      30  #define _GNU_SOURCE 1
      31  #endif
      32  
      33  #include "tconfig.h"
      34  #include "tsystem.h"
      35  #if !defined(inhibit_libc) && !defined(__OpenBSD__)
      36  #include <elf.h>		/* Get DT_CONFIG.  */
      37  #endif
      38  #include "coretypes.h"
      39  #include "tm.h"
      40  #include "libgcc_tm.h"
      41  #include "dwarf2.h"
      42  #include "unwind.h"
      43  #define NO_BASE_OF_ENCODED_VALUE
      44  #include "unwind-pe.h"
      45  #include "unwind-dw2-fde.h"
      46  #include "unwind-compat.h"
      47  #include "gthr.h"
      48  
      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
      53  #endif
      54  
      55  #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
      56      && defined(__BIONIC__)
      57  # define USE_PT_GNU_EH_FRAME
      58  #endif
      59  
      60  #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
      61      && defined(TARGET_DL_ITERATE_PHDR) \
      62      && defined(__linux__)
      63  # define USE_PT_GNU_EH_FRAME
      64  #endif
      65  
      66  #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
      67      && defined(TARGET_DL_ITERATE_PHDR) \
      68      && (defined(__DragonFly__) || defined(__FreeBSD__))
      69  # define ElfW __ElfN
      70  # define USE_PT_GNU_EH_FRAME
      71  #endif
      72  
      73  #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
      74      && defined(TARGET_DL_ITERATE_PHDR) \
      75      && (defined(__OpenBSD__) || defined(__NetBSD__))
      76  # define ElfW(type) Elf_##type
      77  # define USE_PT_GNU_EH_FRAME
      78  #endif
      79  
      80  #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
      81      && defined(TARGET_DL_ITERATE_PHDR) \
      82      && defined(__sun__) && defined(__svr4__)
      83  # define USE_PT_GNU_EH_FRAME
      84  #endif
      85  
      86  #if defined(USE_PT_GNU_EH_FRAME)
      87  
      88  #include <link.h>
      89  
      90  #ifndef __RELOC_POINTER
      91  # define __RELOC_POINTER(ptr, base) ((ptr) + (base))
      92  #endif
      93  
      94  static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases);
      95  
      96  #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
      97  #include "unwind-dw2-fde.c"
      98  #undef _Unwind_Find_FDE
      99  
     100  #ifndef PT_GNU_EH_FRAME
     101  #define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
     102  #endif
     103  
     104  #ifdef CRT_GET_RFIB_DATA
     105  #define NEED_DBASE_MEMBER 1
     106  #else
     107  #define NEED_DBASE_MEMBER 0
     108  #endif
     109  
     110  struct unw_eh_callback_data
     111  {
     112    _Unwind_Ptr pc;
     113  #if NEED_DBASE_MEMBER
     114    void *dbase;
     115  #endif
     116    const struct unw_eh_frame_hdr *hdr;
     117    int check_cache;
     118  };
     119  
     120  /* Returns DATA->dbase if available, else NULL.  */
     121  static inline _Unwind_Ptr
     122  unw_eh_callback_data_dbase (const struct unw_eh_callback_data *data
     123  			    __attribute__ ((unused)))
     124  {
     125  #if NEED_DBASE_MEMBER
     126    return (_Unwind_Ptr) data->dbase;
     127  #else
     128    return 0;
     129  #endif
     130  }
     131  
     132  struct unw_eh_frame_hdr
     133  {
     134    unsigned char version;
     135    unsigned char eh_frame_ptr_enc;
     136    unsigned char fde_count_enc;
     137    unsigned char table_enc;
     138  };
     139  
     140  #define FRAME_HDR_CACHE_SIZE 8
     141  
     142  static struct frame_hdr_cache_element
     143  {
     144    _Unwind_Ptr pc_low;
     145    _Unwind_Ptr pc_high;
     146  #if defined __FRV_FDPIC__ || defined __BFIN_FDPIC__
     147    struct elf32_fdpic_loadaddr load_base;
     148  #else
     149    _Unwind_Ptr load_base;
     150  #endif
     151    const ElfW(Phdr) *p_eh_frame_hdr;
     152    const ElfW(Phdr) *p_dynamic;
     153    struct frame_hdr_cache_element *link;
     154  } frame_hdr_cache[FRAME_HDR_CACHE_SIZE];
     155  
     156  static struct frame_hdr_cache_element *frame_hdr_cache_head;
     157  
     158  /* Like base_of_encoded_value, but take the base from a struct
     159     unw_eh_callback_data instead of an _Unwind_Context.  */
     160  
     161  static inline _Unwind_Ptr
     162  base_from_cb_data (unsigned char encoding __attribute__ ((unused)),
     163  		   _Unwind_Ptr dbase __attribute__ ((unused)))
     164  {
     165  #if NEED_DBASE_MEMBER
     166    if (encoding == DW_EH_PE_omit)
     167      return 0;
     168  
     169    switch (encoding & 0x70)
     170      {
     171      case DW_EH_PE_absptr:
     172      case DW_EH_PE_pcrel:
     173      case DW_EH_PE_aligned:
     174        return 0;
     175  
     176      case DW_EH_PE_textrel:
     177        return 0;
     178      case DW_EH_PE_datarel:
     179        return dbase;
     180      default:
     181        gcc_unreachable ();
     182      }
     183  #else /* !NEED_DBASE_MEMBER */
     184    return 0;
     185  #endif
     186  }
     187  
     188  static int
     189  _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
     190  {
     191    struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
     192    const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
     193    long n, match;
     194  #if defined __FRV_FDPIC__ || defined __BFIN_FDPIC__
     195    struct elf32_fdpic_loadaddr load_base;
     196  #else
     197    _Unwind_Ptr load_base;
     198  #endif
     199    _Unwind_Ptr pc_low = 0, pc_high = 0;
     200  
     201    struct ext_dl_phdr_info
     202      {
     203        ElfW(Addr) dlpi_addr;
     204        const char *dlpi_name;
     205        const ElfW(Phdr) *dlpi_phdr;
     206        ElfW(Half) dlpi_phnum;
     207        unsigned long long int dlpi_adds;
     208        unsigned long long int dlpi_subs;
     209      };
     210  
     211    match = 0;
     212    phdr = info->dlpi_phdr;
     213    load_base = info->dlpi_addr;
     214    p_eh_frame_hdr = NULL;
     215    p_dynamic = NULL;
     216  
     217    struct frame_hdr_cache_element *prev_cache_entry = NULL,
     218      *last_cache_entry = NULL;
     219  
     220    if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info))
     221      {
     222        static unsigned long long adds = -1ULL, subs;
     223        struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info;
     224  
     225        /* We use a least recently used cache replacement policy.  Also,
     226  	 the most recently used cache entries are placed at the head
     227  	 of the search chain.  */
     228  
     229        if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs)
     230  	{
     231  	  /* Find data->pc in shared library cache.
     232  	     Set load_base, p_eh_frame_hdr and p_dynamic
     233  	     plus match from the cache and goto
     234  	     "Read .eh_frame_hdr header." below.  */
     235  
     236  	  struct frame_hdr_cache_element *cache_entry;
     237  
     238  	  for (cache_entry = frame_hdr_cache_head;
     239  	       cache_entry;
     240  	       cache_entry = cache_entry->link)
     241  	    {
     242  	      if (data->pc >= cache_entry->pc_low
     243  		  && data->pc < cache_entry->pc_high)
     244  		{
     245  		  load_base = cache_entry->load_base;
     246  		  p_eh_frame_hdr = cache_entry->p_eh_frame_hdr;
     247  		  p_dynamic = cache_entry->p_dynamic;
     248  
     249  		  /* And move the entry we're using to the head.  */
     250  		  if (cache_entry != frame_hdr_cache_head)
     251  		    {
     252  		      prev_cache_entry->link = cache_entry->link;
     253  		      cache_entry->link = frame_hdr_cache_head;
     254  		      frame_hdr_cache_head = cache_entry;
     255  		    }
     256  		  goto found;
     257  		}
     258  
     259  	      last_cache_entry = cache_entry;
     260  	      /* Exit early if we found an unused entry.  */
     261  	      if ((cache_entry->pc_low | cache_entry->pc_high) == 0)
     262  		break;
     263  	      if (cache_entry->link != NULL)
     264  		prev_cache_entry = cache_entry;
     265  	    }
     266  	}
     267        else
     268  	{
     269  	  adds = einfo->dlpi_adds;
     270  	  subs = einfo->dlpi_subs;
     271  	  /* Initialize the cache.  Create a chain of cache entries,
     272  	     with the final one terminated by a NULL link.  */
     273  	  int i;
     274  	  for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++)
     275  	    {
     276  	      frame_hdr_cache[i].pc_low = 0;
     277  	      frame_hdr_cache[i].pc_high = 0;
     278  	      frame_hdr_cache[i].link = &frame_hdr_cache[i+1];
     279  	    }
     280  	  frame_hdr_cache[i-1].link = NULL;
     281  	  frame_hdr_cache_head = &frame_hdr_cache[0];
     282  	  data->check_cache = 0;
     283  	}
     284      }
     285  
     286    /* Make sure struct dl_phdr_info is at least as big as we need.  */
     287    if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
     288  	     + sizeof (info->dlpi_phnum))
     289      return -1;
     290  
     291    /* See if PC falls into one of the loaded segments.  Find the eh_frame
     292       segment at the same time.  */
     293    for (n = info->dlpi_phnum; --n >= 0; phdr++)
     294      {
     295        if (phdr->p_type == PT_LOAD)
     296  	{
     297  	  _Unwind_Ptr vaddr = (_Unwind_Ptr)
     298  	    __RELOC_POINTER (phdr->p_vaddr, load_base);
     299  	  if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
     300  	    {
     301  	      match = 1;
     302  	      pc_low = vaddr;
     303  	      pc_high =  vaddr + phdr->p_memsz;
     304  	    }
     305  	}
     306        else if (phdr->p_type == PT_GNU_EH_FRAME)
     307  	p_eh_frame_hdr = phdr;
     308  #ifdef PT_SUNW_UNWIND
     309        /* Sun ld emits PT_SUNW_UNWIND .eh_frame_hdr sections instead of
     310  	 PT_SUNW_EH_FRAME/PT_GNU_EH_FRAME, so accept them as well.  */
     311        else if (phdr->p_type == PT_SUNW_UNWIND)
     312  	p_eh_frame_hdr = phdr;
     313  #endif
     314        else if (phdr->p_type == PT_DYNAMIC)
     315  	p_dynamic = phdr;
     316      }
     317  
     318    if (!match)
     319      return 0;
     320  
     321    if (size >= sizeof (struct ext_dl_phdr_info))
     322      {
     323        /* Move the cache entry we're about to overwrite to the head of
     324  	 the list.  If either last_cache_entry or prev_cache_entry are
     325  	 NULL, that cache entry is already at the head.  */
     326        if (last_cache_entry != NULL && prev_cache_entry != NULL)
     327  	{
     328  	  prev_cache_entry->link = last_cache_entry->link;
     329  	  last_cache_entry->link = frame_hdr_cache_head;
     330  	  frame_hdr_cache_head = last_cache_entry;
     331  	}
     332  
     333        frame_hdr_cache_head->load_base = load_base;
     334        frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr;
     335        frame_hdr_cache_head->p_dynamic = p_dynamic;
     336        frame_hdr_cache_head->pc_low = pc_low;
     337        frame_hdr_cache_head->pc_high = pc_high;
     338      }
     339  
     340   found:
     341  
     342    if (!p_eh_frame_hdr)
     343      return 0;
     344  
     345    /* Read .eh_frame_hdr header.  */
     346    data->hdr = (const struct unw_eh_frame_hdr *)
     347      __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
     348  
     349  #ifdef CRT_GET_RFIB_DATA
     350  # if defined __i386__ || defined __nios2__
     351    data->dbase = NULL;
     352    if (p_dynamic)
     353      {
     354        /* For dynamically linked executables and shared libraries,
     355  	 DT_PLTGOT is the gp value for that object.  */
     356        ElfW(Dyn) *dyn = (ElfW(Dyn) *)
     357  	__RELOC_POINTER (p_dynamic->p_vaddr, load_base);
     358        for (; dyn->d_tag != DT_NULL ; dyn++)
     359  	if (dyn->d_tag == DT_PLTGOT)
     360  	  {
     361  	    data->dbase = (void *) dyn->d_un.d_ptr;
     362  #if defined __linux__
     363  	    /* On IA-32 Linux, _DYNAMIC is writable and GLIBC has
     364  	       relocated it.  */
     365  #elif defined __sun__ && defined __svr4__
     366  	    /* On Solaris 2/x86, we need to do this ourselves.  */
     367  	    data->dbase += load_base;
     368  #endif
     369  	    break;
     370  	  }
     371      }
     372  # elif (defined __FRV_FDPIC__ || defined __BFIN_FDPIC__) && defined __linux__
     373    data->dbase = load_base.got_value;
     374  # else
     375  #  error What is DW_EH_PE_datarel base on this platform?
     376  # endif
     377  #endif
     378  
     379    return 1;
     380  }
     381  
     382  /* Find the FDE for the program counter PC, in a previously located
     383     PT_GNU_EH_FRAME data region.  *BASES is updated if an FDE to return is
     384     found.  */
     385  
     386  static const fde *
     387  find_fde_tail (_Unwind_Ptr pc,
     388  	       const struct unw_eh_frame_hdr *hdr,
     389  	       _Unwind_Ptr dbase,
     390  	       struct dwarf_eh_bases *bases)
     391  {
     392    const unsigned char *p = (const unsigned char *) (hdr + 1);
     393    _Unwind_Ptr eh_frame;
     394    struct object ob;
     395  
     396    if (hdr->version != 1)
     397      return NULL;
     398  
     399    if (__builtin_expect (hdr->eh_frame_ptr_enc == (DW_EH_PE_sdata4
     400  						  | DW_EH_PE_pcrel), 1))
     401      {
     402        /* Specialized version of read_encoded_value_with_base, based on what
     403  	 BFD ld generates.  */
     404        signed value __attribute__ ((mode (SI)));
     405        memcpy (&value, p, sizeof (value));
     406        eh_frame = (_Unwind_Ptr) (p + value);
     407        p += sizeof (value);
     408      }
     409    else
     410      p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
     411  				      base_from_cb_data (hdr->eh_frame_ptr_enc,
     412  							 dbase),
     413  				      p, &eh_frame);
     414  
     415    /* We require here specific table encoding to speed things up.
     416       Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
     417       as base, not the processor specific DW_EH_PE_datarel.  */
     418    if (hdr->fde_count_enc != DW_EH_PE_omit
     419        && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
     420      {
     421        _Unwind_Ptr fde_count;
     422  
     423        if (__builtin_expect (hdr->fde_count_enc == DW_EH_PE_udata4, 1))
     424  	{
     425  	  /* Specialized version of read_encoded_value_with_base, based on
     426  	     what BFD ld generates.  */
     427  	  unsigned value __attribute__ ((mode (SI)));
     428  	  memcpy (&value, p, sizeof (value));
     429  	  p += sizeof (value);
     430  	  fde_count = value;
     431  	}
     432        else
     433  	p = read_encoded_value_with_base (hdr->fde_count_enc,
     434  					  base_from_cb_data (hdr->fde_count_enc,
     435  							     dbase),
     436  					  p, &fde_count);
     437        /* Shouldn't happen.  */
     438        if (fde_count == 0)
     439  	return NULL;
     440        if ((((_Unwind_Ptr) p) & 3) == 0)
     441  	{
     442  	  struct fde_table {
     443  	    signed initial_loc __attribute__ ((mode (SI)));
     444  	    signed fde __attribute__ ((mode (SI)));
     445  	  };
     446  	  const struct fde_table *table = (const struct fde_table *) p;
     447  	  size_t lo, hi, mid;
     448  	  _Unwind_Ptr data_base = (_Unwind_Ptr) hdr;
     449  	  fde *f;
     450  	  unsigned int f_enc, f_enc_size;
     451  	  _Unwind_Ptr range;
     452  
     453  	  mid = fde_count - 1;
     454  	  if (pc < table[0].initial_loc + data_base)
     455  	    return NULL;
     456  	  else if (pc < table[mid].initial_loc + data_base)
     457  	    {
     458  	      lo = 0;
     459  	      hi = mid;
     460  
     461  	      while (lo < hi)
     462  		{
     463  		  mid = (lo + hi) / 2;
     464  		  if (pc < table[mid].initial_loc + data_base)
     465  		    hi = mid;
     466  		  else if (pc >= table[mid + 1].initial_loc + data_base)
     467  		    lo = mid + 1;
     468  		  else
     469  		    break;
     470  		}
     471  
     472  	      gcc_assert (lo < hi);
     473  	    }
     474  
     475  	  f = (fde *) (table[mid].fde + data_base);
     476  	  f_enc = get_fde_encoding (f);
     477  	  f_enc_size = size_of_encoded_value (f_enc);
     478  
     479  	  /* BFD ld uses DW_EH_PE_sdata4 | DW_EH_PE_pcrel on non-FDPIC targets,
     480  	     so optimize for that.
     481  
     482  	     This optimization is not valid for FDPIC targets.  f_enc & 0x0f as
     483  	     passed to read_encoded_value_with_base masks away the base flags,
     484  	     but they are implicit for FDPIC.  */
     485  #ifndef __FDPIC__
     486  	  if (__builtin_expect (f_enc == (DW_EH_PE_sdata4 | DW_EH_PE_pcrel),
     487  				1))
     488  	    {
     489  	      signed value __attribute__ ((mode (SI)));
     490  	      memcpy (&value, &f->pc_begin[f_enc_size], sizeof (value));
     491  	      range = value;
     492  	    }
     493  	  else
     494  #endif
     495  	    read_encoded_value_with_base (f_enc & 0x0f, 0,
     496  					  &f->pc_begin[f_enc_size], &range);
     497  	  _Unwind_Ptr func = table[mid].initial_loc + data_base;
     498  	  if (pc < table[mid].initial_loc + data_base + range)
     499  	    {
     500  	      bases->tbase = NULL;
     501  	      bases->dbase = (void *) dbase;
     502  	      bases->func = (void *) func;
     503  	      return f;
     504  	    }
     505  	  else
     506  	    return NULL;
     507  	}
     508      }
     509  
     510    /* We have no sorted search table, so need to go the slow way.
     511       As soon as GLIBC will provide API so to notify that a library has been
     512       removed, we could cache this (and thus use search_object).  */
     513    ob.pc_begin = NULL;
     514    ob.tbase = NULL;
     515    ob.dbase = (void *) dbase;
     516    ob.u.single = (fde *) eh_frame;
     517    ob.s.i = 0;
     518    ob.s.b.mixed_encoding = 1;  /* Need to assume worst case.  */
     519    const fde *entry = linear_search_fdes (&ob, (fde *) eh_frame, (void *) pc);
     520    if (entry != NULL)
     521      {
     522        _Unwind_Ptr func;
     523        unsigned int encoding = get_fde_encoding (entry);
     524  
     525        read_encoded_value_with_base (encoding,
     526  				    base_from_cb_data (encoding, dbase),
     527  				    entry->pc_begin, &func);
     528        bases->tbase = NULL;
     529        bases->dbase = (void *) dbase;
     530        bases->func = (void *) func;
     531      }
     532    return entry;
     533  }
     534  
     535  const fde *
     536  _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
     537  {
     538    struct unw_eh_callback_data data;
     539    const fde *ret;
     540  
     541    ret = _Unwind_Find_registered_FDE (pc, bases);
     542    if (ret != NULL)
     543      return ret;
     544  
     545    /* Use DLFO_STRUCT_HAS_EH_DBASE as a proxy for the existence of a glibc-style
     546       _dl_find_object function.  */
     547  #ifdef DLFO_STRUCT_HAS_EH_DBASE
     548    {
     549      struct dl_find_object dlfo;
     550      if (_dl_find_object (pc, &dlfo) == 0 && dlfo.dlfo_eh_frame != NULL)
     551        return find_fde_tail ((_Unwind_Ptr) pc, dlfo.dlfo_eh_frame,
     552  # if DLFO_STRUCT_HAS_EH_DBASE
     553  			    (_Unwind_Ptr) dlfo.dlfo_eh_dbase,
     554  # else
     555  			    0,
     556  # endif
     557  			    bases);
     558      else
     559        return NULL;
     560      }
     561  #endif /* DLFO_STRUCT_HAS_EH_DBASE */
     562  
     563    data.pc = (_Unwind_Ptr) pc;
     564  #if NEED_DBASE_MEMBER
     565    data.dbase = NULL;
     566  #endif
     567    data.check_cache = 1;
     568  
     569    if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) <= 0)
     570      return NULL;
     571  
     572    _Unwind_Ptr dbase = unw_eh_callback_data_dbase (&data);
     573    return find_fde_tail ((_Unwind_Ptr) pc, data.hdr, dbase, bases);
     574  }
     575  
     576  #else
     577  /* Prevent multiple include of header files.  */
     578  #define _Unwind_Find_FDE _Unwind_Find_FDE
     579  #include "unwind-dw2-fde.c"
     580  #endif
     581  
     582  #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
     583  alias (_Unwind_Find_FDE);
     584  #endif