Blame sysdeps/generic/unwind-dw2-fde.c

Packit 6c4009
/* Subroutines needed for unwinding stack frames for exception handling.  */
Packit 6c4009
/* Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   Contributed by Jason Merrill <jason@cygnus.com>.
Packit 6c4009
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# include <shlib-compat.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if !defined _LIBC || SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2_5)
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include <dwarf2.h>
Packit 6c4009
#include <unwind.h>
Packit 6c4009
#define NO_BASE_OF_ENCODED_VALUE
Packit 6c4009
#include <unwind-pe.h>
Packit 6c4009
#include <unwind-dw2-fde.h>
Packit 6c4009
#else
Packit 6c4009
#ifndef _Unwind_Find_FDE
Packit 6c4009
#include "tconfig.h"
Packit 6c4009
#include "tsystem.h"
Packit 6c4009
#include "dwarf2.h"
Packit 6c4009
#include "unwind.h"
Packit 6c4009
#define NO_BASE_OF_ENCODED_VALUE
Packit 6c4009
#include "unwind-pe.h"
Packit 6c4009
#include "unwind-dw2-fde.h"
Packit 6c4009
#include "gthr.h"
Packit 6c4009
#endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* The unseen_objects list contains objects that have been registered
Packit 6c4009
   but not yet categorized in any way.  The seen_objects list has had
Packit 6c4009
   it's pc_begin and count fields initialized at minimum, and is sorted
Packit 6c4009
   by decreasing value of pc_begin.  */
Packit 6c4009
static struct object *unseen_objects;
Packit 6c4009
static struct object *seen_objects;
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
Packit 6c4009
__libc_lock_define_initialized (static, object_mutex)
Packit 6c4009
#define init_object_mutex_once()
Packit 6c4009
#define __gthread_mutex_lock(m) __libc_lock_lock (*(m))
Packit 6c4009
#define __gthread_mutex_unlock(m) __libc_lock_unlock (*(m))
Packit 6c4009
Packit 6c4009
void __register_frame_info_bases (void *begin, struct object *ob,
Packit 6c4009
				  void *tbase, void *dbase);
Packit 6c4009
hidden_proto (__register_frame_info_bases)
Packit 6c4009
void __register_frame_info_table_bases (void *begin,
Packit 6c4009
					struct object *ob,
Packit 6c4009
					void *tbase, void *dbase);
Packit 6c4009
hidden_proto (__register_frame_info_table_bases)
Packit 6c4009
void *__deregister_frame_info_bases (void *begin);
Packit 6c4009
hidden_proto (__deregister_frame_info_bases)
Packit 6c4009
Packit 6c4009
#else
Packit 6c4009
Packit 6c4009
#ifdef __GTHREAD_MUTEX_INIT
Packit 6c4009
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
Packit 6c4009
#else
Packit 6c4009
static __gthread_mutex_t object_mutex;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
Packit 6c4009
static void
Packit 6c4009
init_object_mutex (void)
Packit 6c4009
{
Packit 6c4009
  __GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
init_object_mutex_once (void)
Packit 6c4009
{
Packit 6c4009
  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
Packit 6c4009
  __gthread_once (&once, init_object_mutex);
Packit 6c4009
}
Packit 6c4009
#else
Packit 6c4009
#define init_object_mutex_once()
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#endif /* _LIBC */
Packit 6c4009
Packit 6c4009
/* Called from crtbegin.o to register the unwind info for an object.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__register_frame_info_bases (void *begin, struct object *ob,
Packit 6c4009
			     void *tbase, void *dbase)
Packit 6c4009
{
Packit 6c4009
  /* If .eh_frame is empty, don't register at all.  */
Packit 6c4009
  if (*(uword *) begin == 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  ob->pc_begin = (void *)-1;
Packit 6c4009
  ob->tbase = tbase;
Packit 6c4009
  ob->dbase = dbase;
Packit 6c4009
  ob->u.single = begin;
Packit 6c4009
  ob->s.i = 0;
Packit 6c4009
  ob->s.b.encoding = DW_EH_PE_omit;
Packit 6c4009
#ifdef DWARF2_OBJECT_END_PTR_EXTENSION
Packit 6c4009
  ob->fde_end = NULL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  init_object_mutex_once ();
Packit 6c4009
  __gthread_mutex_lock (&object_mutex);
Packit 6c4009
Packit 6c4009
  ob->next = unseen_objects;
Packit 6c4009
  unseen_objects = ob;
Packit 6c4009
Packit 6c4009
  __gthread_mutex_unlock (&object_mutex);
Packit 6c4009
}
Packit 6c4009
hidden_def (__register_frame_info_bases)
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__register_frame_info (void *begin, struct object *ob)
Packit 6c4009
{
Packit 6c4009
  __register_frame_info_bases (begin, ob, 0, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__register_frame (void *begin)
Packit 6c4009
{
Packit 6c4009
  struct object *ob;
Packit 6c4009
Packit 6c4009
  /* If .eh_frame is empty, don't register at all.  */
Packit 6c4009
  if (*(uword *) begin == 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  ob = (struct object *) malloc (sizeof (struct object));
Packit 6c4009
  __register_frame_info_bases (begin, ob, 0, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Similar, but BEGIN is actually a pointer to a table of unwind entries
Packit 6c4009
   for different translation units.  Called from the file generated by
Packit 6c4009
   collect2.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__register_frame_info_table_bases (void *begin, struct object *ob,
Packit 6c4009
				   void *tbase, void *dbase)
Packit 6c4009
{
Packit 6c4009
  ob->pc_begin = (void *)-1;
Packit 6c4009
  ob->tbase = tbase;
Packit 6c4009
  ob->dbase = dbase;
Packit 6c4009
  ob->u.array = begin;
Packit 6c4009
  ob->s.i = 0;
Packit 6c4009
  ob->s.b.from_array = 1;
Packit 6c4009
  ob->s.b.encoding = DW_EH_PE_omit;
Packit 6c4009
Packit 6c4009
  init_object_mutex_once ();
Packit 6c4009
  __gthread_mutex_lock (&object_mutex);
Packit 6c4009
Packit 6c4009
  ob->next = unseen_objects;
Packit 6c4009
  unseen_objects = ob;
Packit 6c4009
Packit 6c4009
  __gthread_mutex_unlock (&object_mutex);
Packit 6c4009
}
Packit 6c4009
hidden_def (__register_frame_info_table_bases)
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__register_frame_info_table (void *begin, struct object *ob)
Packit 6c4009
{
Packit 6c4009
  __register_frame_info_table_bases (begin, ob, 0, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__register_frame_table (void *begin)
Packit 6c4009
{
Packit 6c4009
  struct object *ob = (struct object *) malloc (sizeof (struct object));
Packit 6c4009
  __register_frame_info_table_bases (begin, ob, 0, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Called from crtbegin.o to deregister the unwind info for an object.  */
Packit 6c4009
/* ??? Glibc has for a while now exported __register_frame_info and
Packit 6c4009
   __deregister_frame_info.  If we call __register_frame_info_bases
Packit 6c4009
   from crtbegin (wherein it is declared weak), and this object does
Packit 6c4009
   not get pulled from libgcc.a for other reasons, then the
Packit 6c4009
   invocation of __deregister_frame_info will be resolved from glibc.
Packit 6c4009
   Since the registration did not happen there, we'll abort.
Packit 6c4009
Packit 6c4009
   Therefore, declare a new deregistration entry point that does the
Packit 6c4009
   exact same thing, but will resolve to the same library as
Packit 6c4009
   implements __register_frame_info_bases.  */
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
__deregister_frame_info_bases (void *begin)
Packit 6c4009
{
Packit 6c4009
  struct object **p;
Packit 6c4009
  struct object *ob = 0;
Packit 6c4009
  struct fde_vector *tofree = NULL;
Packit 6c4009
Packit 6c4009
  /* If .eh_frame is empty, we haven't registered.  */
Packit 6c4009
  if (*(uword *) begin == 0)
Packit 6c4009
    return ob;
Packit 6c4009
Packit 6c4009
  init_object_mutex_once ();
Packit 6c4009
  __gthread_mutex_lock (&object_mutex);
Packit 6c4009
Packit 6c4009
  for (p = &unseen_objects; *p ; p = &(*p)->next)
Packit 6c4009
    if ((*p)->u.single == begin)
Packit 6c4009
      {
Packit 6c4009
	ob = *p;
Packit 6c4009
	*p = ob->next;
Packit 6c4009
	goto out;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  for (p = &seen_objects; *p ; p = &(*p)->next)
Packit 6c4009
    if ((*p)->s.b.sorted)
Packit 6c4009
      {
Packit 6c4009
	if ((*p)->u.sort->orig_data == begin)
Packit 6c4009
	  {
Packit 6c4009
	    ob = *p;
Packit 6c4009
	    *p = ob->next;
Packit 6c4009
	    tofree = ob->u.sort;
Packit 6c4009
	    goto out;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
    else
Packit 6c4009
      {
Packit 6c4009
	if ((*p)->u.single == begin)
Packit 6c4009
	  {
Packit 6c4009
	    ob = *p;
Packit 6c4009
	    *p = ob->next;
Packit 6c4009
	    goto out;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  __gthread_mutex_unlock (&object_mutex);
Packit 6c4009
  abort ();
Packit 6c4009
Packit 6c4009
 out:
Packit 6c4009
  __gthread_mutex_unlock (&object_mutex);
Packit 6c4009
  free (tofree);
Packit 6c4009
  return (void *) ob;
Packit 6c4009
}
Packit 6c4009
hidden_def (__deregister_frame_info_bases)
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
__deregister_frame_info (void *begin)
Packit 6c4009
{
Packit 6c4009
  return __deregister_frame_info_bases (begin);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__deregister_frame (void *begin)
Packit 6c4009
{
Packit 6c4009
  /* If .eh_frame is empty, we haven't registered.  */
Packit 6c4009
  if (*(uword *) begin != 0)
Packit 6c4009
    free (__deregister_frame_info_bases (begin));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009

Packit 6c4009
/* Like base_of_encoded_value, but take the base from a struct object
Packit 6c4009
   instead of an _Unwind_Context.  */
Packit 6c4009
Packit 6c4009
static _Unwind_Ptr
Packit 6c4009
base_from_object (unsigned char encoding, struct object *ob)
Packit 6c4009
{
Packit 6c4009
  if (encoding == DW_EH_PE_omit)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  switch (encoding & 0x70)
Packit 6c4009
    {
Packit 6c4009
    case DW_EH_PE_absptr:
Packit 6c4009
    case DW_EH_PE_pcrel:
Packit 6c4009
    case DW_EH_PE_aligned:
Packit 6c4009
      return 0;
Packit 6c4009
Packit 6c4009
    case DW_EH_PE_textrel:
Packit 6c4009
      return (_Unwind_Ptr) ob->tbase;
Packit 6c4009
    case DW_EH_PE_datarel:
Packit 6c4009
      return (_Unwind_Ptr) ob->dbase;
Packit 6c4009
    }
Packit 6c4009
  abort ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Return the FDE pointer encoding from the CIE.  */
Packit 6c4009
/* ??? This is a subset of extract_cie_info from unwind-dw2.c.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
get_cie_encoding (struct dwarf_cie *cie)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *aug, *p;
Packit 6c4009
  _Unwind_Ptr dummy;
Packit 6c4009
  _Unwind_Word utmp;
Packit 6c4009
  _Unwind_Sword stmp;
Packit 6c4009
Packit 6c4009
  aug = cie->augmentation;
Packit 6c4009
  if (aug[0] != 'z')
Packit 6c4009
    return DW_EH_PE_absptr;
Packit 6c4009
Packit 6c4009
  /* Skip the augmentation string.  */
Packit 6c4009
  p = aug + strlen ((const char *) aug) + 1;
Packit 6c4009
  p = read_uleb128 (p, &utmp);		/* Skip code alignment.  */
Packit 6c4009
  p = read_sleb128 (p, &stmp);		/* Skip data alignment.  */
Packit 6c4009
  p++;					/* Skip return address column.  */
Packit 6c4009
Packit 6c4009
  aug++;				/* Skip 'z' */
Packit 6c4009
  p = read_uleb128 (p, &utmp);		/* Skip augmentation length.  */
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* This is what we're looking for.  */
Packit 6c4009
      if (*aug == 'R')
Packit 6c4009
	return *p;
Packit 6c4009
      /* Personality encoding and pointer.  */
Packit 6c4009
      else if (*aug == 'P')
Packit 6c4009
	{
Packit 6c4009
	  /* ??? Avoid dereferencing indirect pointers, since we're
Packit 6c4009
	     faking the base address.  Gotta keep DW_EH_PE_aligned
Packit 6c4009
	     intact, however.  */
Packit 6c4009
	  p = read_encoded_value_with_base (*p & 0x7F, 0, p + 1, &dummy);
Packit 6c4009
	}
Packit 6c4009
      /* LSDA encoding.  */
Packit 6c4009
      else if (*aug == 'L')
Packit 6c4009
	p++;
Packit 6c4009
      /* Otherwise end of string, or unknown augmentation.  */
Packit 6c4009
      else
Packit 6c4009
	return DW_EH_PE_absptr;
Packit 6c4009
      aug++;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
get_fde_encoding (struct dwarf_fde *f)
Packit 6c4009
{
Packit 6c4009
  return get_cie_encoding (get_cie (f));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009

Packit 6c4009
/* Sorting an array of FDEs by address.
Packit 6c4009
   (Ideally we would have the linker sort the FDEs so we don't have to do
Packit 6c4009
   it at run time. But the linkers are not yet prepared for this.)  */
Packit 6c4009
Packit 6c4009
/* Return the Nth pc_begin value from FDE x.  */
Packit 6c4009
Packit 6c4009
static inline _Unwind_Ptr
Packit 6c4009
get_pc_begin (fde *x, size_t n)
Packit 6c4009
{
Packit 6c4009
  _Unwind_Ptr p;
Packit 6c4009
  memcpy (&p, x->pc_begin + n * sizeof (_Unwind_Ptr), sizeof (_Unwind_Ptr));
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Comparison routines.  Three variants of increasing complexity.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
fde_unencoded_compare (struct object *ob __attribute__((unused)),
Packit 6c4009
		       fde *x, fde *y)
Packit 6c4009
{
Packit 6c4009
  _Unwind_Ptr x_ptr = get_pc_begin (x, 0);
Packit 6c4009
  _Unwind_Ptr y_ptr = get_pc_begin (y, 0);
Packit 6c4009
Packit 6c4009
  if (x_ptr > y_ptr)
Packit 6c4009
    return 1;
Packit 6c4009
  if (x_ptr < y_ptr)
Packit 6c4009
    return -1;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
fde_single_encoding_compare (struct object *ob, fde *x, fde *y)
Packit 6c4009
{
Packit 6c4009
  _Unwind_Ptr base, x_ptr, y_ptr;
Packit 6c4009
Packit 6c4009
  base = base_from_object (ob->s.b.encoding, ob);
Packit 6c4009
  read_encoded_value_with_base (ob->s.b.encoding, base, x->pc_begin, &x_ptr);
Packit 6c4009
  read_encoded_value_with_base (ob->s.b.encoding, base, y->pc_begin, &y_ptr);
Packit 6c4009
Packit 6c4009
  if (x_ptr > y_ptr)
Packit 6c4009
    return 1;
Packit 6c4009
  if (x_ptr < y_ptr)
Packit 6c4009
    return -1;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
fde_mixed_encoding_compare (struct object *ob, fde *x, fde *y)
Packit 6c4009
{
Packit 6c4009
  int x_encoding, y_encoding;
Packit 6c4009
  _Unwind_Ptr x_ptr, y_ptr;
Packit 6c4009
Packit 6c4009
  x_encoding = get_fde_encoding (x);
Packit 6c4009
  read_encoded_value_with_base (x_encoding, base_from_object (x_encoding, ob),
Packit 6c4009
				x->pc_begin, &x_ptr);
Packit 6c4009
Packit 6c4009
  y_encoding = get_fde_encoding (y);
Packit 6c4009
  read_encoded_value_with_base (y_encoding, base_from_object (y_encoding, ob),
Packit 6c4009
				y->pc_begin, &y_ptr);
Packit 6c4009
Packit 6c4009
  if (x_ptr > y_ptr)
Packit 6c4009
    return 1;
Packit 6c4009
  if (x_ptr < y_ptr)
Packit 6c4009
    return -1;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
typedef int (*fde_compare_t) (struct object *, fde *, fde *);
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is a special mix of insertion sort and heap sort, optimized for
Packit 6c4009
   the data sets that actually occur. They look like
Packit 6c4009
   101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
Packit 6c4009
   I.e. a linearly increasing sequence (coming from functions in the text
Packit 6c4009
   section), with additionally a few unordered elements (coming from functions
Packit 6c4009
   in gnu_linkonce sections) whose values are higher than the values in the
Packit 6c4009
   surrounding linear sequence (but not necessarily higher than the values
Packit 6c4009
   at the end of the linear sequence!).
Packit 6c4009
   The worst-case total run time is O(N) + O(n log (n)), where N is the
Packit 6c4009
   total number of FDEs and n is the number of erratic ones.  */
Packit 6c4009
Packit 6c4009
struct fde_accumulator
Packit 6c4009
{
Packit 6c4009
  struct fde_vector *linear;
Packit 6c4009
  struct fde_vector *erratic;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
start_fde_sort (struct fde_accumulator *accu, size_t count)
Packit 6c4009
{
Packit 6c4009
  size_t size;
Packit 6c4009
  if (! count)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  size = sizeof (struct fde_vector) + sizeof (fde *) * count;
Packit 6c4009
  if ((accu->linear = (struct fde_vector *) malloc (size)))
Packit 6c4009
    {
Packit 6c4009
      accu->linear->count = 0;
Packit 6c4009
      if ((accu->erratic = (struct fde_vector *) malloc (size)))
Packit 6c4009
	accu->erratic->count = 0;
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
fde_insert (struct fde_accumulator *accu, fde *this_fde)
Packit 6c4009
{
Packit 6c4009
  if (accu->linear)
Packit 6c4009
    accu->linear->array[accu->linear->count++] = this_fde;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Split LINEAR into a linear sequence with low values and an erratic
Packit 6c4009
   sequence with high values, put the linear one (of longest possible
Packit 6c4009
   length) into LINEAR and the erratic one into ERRATIC. This is O(N).
Packit 6c4009
Packit 6c4009
   Because the longest linear sequence we are trying to locate within the
Packit 6c4009
   incoming LINEAR array can be interspersed with (high valued) erratic
Packit 6c4009
   entries.  We construct a chain indicating the sequenced entries.
Packit 6c4009
   To avoid having to allocate this chain, we overlay it onto the space of
Packit 6c4009
   the ERRATIC array during construction.  A final pass iterates over the
Packit 6c4009
   chain to determine what should be placed in the ERRATIC array, and
Packit 6c4009
   what is the linear sequence.  This overlay is safe from aliasing.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
fde_split (struct object *ob, fde_compare_t fde_compare,
Packit 6c4009
	   struct fde_vector *linear, struct fde_vector *erratic)
Packit 6c4009
{
Packit 6c4009
  static fde *marker;
Packit 6c4009
  size_t count = linear->count;
Packit 6c4009
  fde **chain_end = ▮
Packit 6c4009
  size_t i, j, k;
Packit 6c4009
Packit 6c4009
  /* This should optimize out, but it is wise to make sure this assumption
Packit 6c4009
     is correct. Should these have different sizes, we cannot cast between
Packit 6c4009
     them and the overlaying onto ERRATIC will not work.  */
Packit 6c4009
  if (sizeof (fde *) != sizeof (fde **))
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  for (i = 0; i < count; i++)
Packit 6c4009
    {
Packit 6c4009
      fde **probe;
Packit 6c4009
Packit 6c4009
      for (probe = chain_end;
Packit 6c4009
	   probe != &marker && fde_compare (ob, linear->array[i], *probe) < 0;
Packit 6c4009
	   probe = chain_end)
Packit 6c4009
	{
Packit 6c4009
	  chain_end = (fde **) erratic->array[probe - linear->array];
Packit 6c4009
	  erratic->array[probe - linear->array] = NULL;
Packit 6c4009
	}
Packit 6c4009
      erratic->array[i] = (fde *) chain_end;
Packit 6c4009
      chain_end = &linear->array[i];
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Each entry in LINEAR which is part of the linear sequence we have
Packit 6c4009
     discovered will correspond to a non-NULL entry in the chain we built in
Packit 6c4009
     the ERRATIC array.  */
Packit 6c4009
  for (i = j = k = 0; i < count; i++)
Packit 6c4009
    if (erratic->array[i])
Packit 6c4009
      linear->array[j++] = linear->array[i];
Packit 6c4009
    else
Packit 6c4009
      erratic->array[k++] = linear->array[i];
Packit 6c4009
  linear->count = j;
Packit 6c4009
  erratic->count = k;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This is O(n log(n)).  BSD/OS defines heapsort in stdlib.h, so we must
Packit 6c4009
   use a name that does not conflict.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
frame_heapsort (struct object *ob, fde_compare_t fde_compare,
Packit 6c4009
		struct fde_vector *erratic)
Packit 6c4009
{
Packit 6c4009
  /* For a description of this algorithm, see:
Packit 6c4009
     Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed.,
Packit 6c4009
     p. 60-61.  */
Packit 6c4009
  fde ** a = erratic->array;
Packit 6c4009
  /* A portion of the array is called a "heap" if for all i>=0:
Packit 6c4009
     If i and 2i+1 are valid indices, then a[i] >= a[2i+1].
Packit 6c4009
     If i and 2i+2 are valid indices, then a[i] >= a[2i+2].  */
Packit 6c4009
#define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0)
Packit 6c4009
  size_t n = erratic->count;
Packit 6c4009
  size_t m = n;
Packit 6c4009
  size_t i;
Packit 6c4009
Packit 6c4009
  while (m > 0)
Packit 6c4009
    {
Packit 6c4009
      /* Invariant: a[m..n-1] is a heap.  */
Packit 6c4009
      m--;
Packit 6c4009
      for (i = m; 2*i+1 < n; )
Packit 6c4009
	{
Packit 6c4009
	  if (2*i+2 < n
Packit 6c4009
	      && fde_compare (ob, a[2*i+2], a[2*i+1]) > 0
Packit 6c4009
	      && fde_compare (ob, a[2*i+2], a[i]) > 0)
Packit 6c4009
	    {
Packit 6c4009
	      SWAP (a[i], a[2*i+2]);
Packit 6c4009
	      i = 2*i+2;
Packit 6c4009
	    }
Packit 6c4009
	  else if (fde_compare (ob, a[2*i+1], a[i]) > 0)
Packit 6c4009
	    {
Packit 6c4009
	      SWAP (a[i], a[2*i+1]);
Packit 6c4009
	      i = 2*i+1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  while (n > 1)
Packit 6c4009
    {
Packit 6c4009
      /* Invariant: a[0..n-1] is a heap.  */
Packit 6c4009
      n--;
Packit 6c4009
      SWAP (a[0], a[n]);
Packit 6c4009
      for (i = 0; 2*i+1 < n; )
Packit 6c4009
	{
Packit 6c4009
	  if (2*i+2 < n
Packit 6c4009
	      && fde_compare (ob, a[2*i+2], a[2*i+1]) > 0
Packit 6c4009
	      && fde_compare (ob, a[2*i+2], a[i]) > 0)
Packit 6c4009
	    {
Packit 6c4009
	      SWAP (a[i], a[2*i+2]);
Packit 6c4009
	      i = 2*i+2;
Packit 6c4009
	    }
Packit 6c4009
	  else if (fde_compare (ob, a[2*i+1], a[i]) > 0)
Packit 6c4009
	    {
Packit 6c4009
	      SWAP (a[i], a[2*i+1]);
Packit 6c4009
	      i = 2*i+1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#undef SWAP
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Merge V1 and V2, both sorted, and put the result into V1.  */
Packit 6c4009
static void
Packit 6c4009
fde_merge (struct object *ob, fde_compare_t fde_compare,
Packit 6c4009
	   struct fde_vector *v1, struct fde_vector *v2)
Packit 6c4009
{
Packit 6c4009
  size_t i1, i2;
Packit 6c4009
  fde * fde2;
Packit 6c4009
Packit 6c4009
  i2 = v2->count;
Packit 6c4009
  if (i2 > 0)
Packit 6c4009
    {
Packit 6c4009
      i1 = v1->count;
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  i2--;
Packit 6c4009
	  fde2 = v2->array[i2];
Packit 6c4009
	  while (i1 > 0 && fde_compare (ob, v1->array[i1-1], fde2) > 0)
Packit 6c4009
	    {
Packit 6c4009
	      v1->array[i1+i2] = v1->array[i1-1];
Packit 6c4009
	      i1--;
Packit 6c4009
	    }
Packit 6c4009
	  v1->array[i1+i2] = fde2;
Packit 6c4009
	}
Packit 6c4009
      while (i2 > 0);
Packit 6c4009
      v1->count += v2->count;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
end_fde_sort (struct object *ob, struct fde_accumulator *accu, size_t count)
Packit 6c4009
{
Packit 6c4009
  fde_compare_t fde_compare;
Packit 6c4009
Packit 6c4009
  if (accu->linear->count != count)
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  if (ob->s.b.mixed_encoding)
Packit 6c4009
    fde_compare = fde_mixed_encoding_compare;
Packit 6c4009
  else if (ob->s.b.encoding == DW_EH_PE_absptr)
Packit 6c4009
    fde_compare = fde_unencoded_compare;
Packit 6c4009
  else
Packit 6c4009
    fde_compare = fde_single_encoding_compare;
Packit 6c4009
Packit 6c4009
  if (accu->erratic)
Packit 6c4009
    {
Packit 6c4009
      fde_split (ob, fde_compare, accu->linear, accu->erratic);
Packit 6c4009
      if (accu->linear->count + accu->erratic->count != count)
Packit 6c4009
	abort ();
Packit 6c4009
      frame_heapsort (ob, fde_compare, accu->erratic);
Packit 6c4009
      fde_merge (ob, fde_compare, accu->linear, accu->erratic);
Packit 6c4009
      free (accu->erratic);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* We've not managed to malloc an erratic array,
Packit 6c4009
	 so heap sort in the linear one.  */
Packit 6c4009
      frame_heapsort (ob, fde_compare, accu->linear);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009

Packit 6c4009
/* Update encoding, mixed_encoding, and pc_begin for OB for the
Packit 6c4009
   fde array beginning at THIS_FDE.  Return the number of fdes
Packit 6c4009
   encountered along the way.  */
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
classify_object_over_fdes (struct object *ob, fde *this_fde)
Packit 6c4009
{
Packit 6c4009
  struct dwarf_cie *last_cie = 0;
Packit 6c4009
  size_t count = 0;
Packit 6c4009
  int encoding = DW_EH_PE_absptr;
Packit 6c4009
  _Unwind_Ptr base = 0;
Packit 6c4009
Packit 6c4009
  for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde))
Packit 6c4009
    {
Packit 6c4009
      struct dwarf_cie *this_cie;
Packit 6c4009
      _Unwind_Ptr mask, pc_begin;
Packit 6c4009
Packit 6c4009
      /* Skip CIEs.  */
Packit 6c4009
      if (this_fde->CIE_delta == 0)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      /* Determine the encoding for this FDE.  Note mixed encoded
Packit 6c4009
	 objects for later.  */
Packit 6c4009
      this_cie = get_cie (this_fde);
Packit 6c4009
      if (this_cie != last_cie)
Packit 6c4009
	{
Packit 6c4009
	  last_cie = this_cie;
Packit 6c4009
	  encoding = get_cie_encoding (this_cie);
Packit 6c4009
	  base = base_from_object (encoding, ob);
Packit 6c4009
	  if (ob->s.b.encoding == DW_EH_PE_omit)
Packit 6c4009
	    ob->s.b.encoding = encoding;
Packit 6c4009
	  else if (ob->s.b.encoding != encoding)
Packit 6c4009
	    ob->s.b.mixed_encoding = 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
Packit 6c4009
				    &pc_begin);
Packit 6c4009
Packit 6c4009
      /* Take care to ignore link-once functions that were removed.
Packit 6c4009
	 In these cases, the function address will be NULL, but if
Packit 6c4009
	 the encoding is smaller than a pointer a true NULL may not
Packit 6c4009
	 be representable.  Assume 0 in the representable bits is NULL.  */
Packit 6c4009
      mask = size_of_encoded_value (encoding);
Packit 6c4009
      if (mask < sizeof (void *))
Packit 6c4009
	mask = (1L << (mask << 3)) - 1;
Packit 6c4009
      else
Packit 6c4009
	mask = -1;
Packit 6c4009
Packit 6c4009
      if ((pc_begin & mask) == 0)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      count += 1;
Packit 6c4009
      if ((void *) pc_begin < ob->pc_begin)
Packit 6c4009
	ob->pc_begin = (void *) pc_begin;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return count;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
add_fdes (struct object *ob, struct fde_accumulator *accu, fde *this_fde)
Packit 6c4009
{
Packit 6c4009
  struct dwarf_cie *last_cie = 0;
Packit 6c4009
  int encoding = ob->s.b.encoding;
Packit 6c4009
  _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob);
Packit 6c4009
Packit 6c4009
  for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde))
Packit 6c4009
    {
Packit 6c4009
      struct dwarf_cie *this_cie;
Packit 6c4009
Packit 6c4009
      /* Skip CIEs.  */
Packit 6c4009
      if (this_fde->CIE_delta == 0)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      if (ob->s.b.mixed_encoding)
Packit 6c4009
	{
Packit 6c4009
	  /* Determine the encoding for this FDE.  Note mixed encoded
Packit 6c4009
	     objects for later.  */
Packit 6c4009
	  this_cie = get_cie (this_fde);
Packit 6c4009
	  if (this_cie != last_cie)
Packit 6c4009
	    {
Packit 6c4009
	      last_cie = this_cie;
Packit 6c4009
	      encoding = get_cie_encoding (this_cie);
Packit 6c4009
	      base = base_from_object (encoding, ob);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (encoding == DW_EH_PE_absptr)
Packit 6c4009
	{
Packit 6c4009
	  if (get_pc_begin (this_fde, 0) == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  _Unwind_Ptr pc_begin, mask;
Packit 6c4009
Packit 6c4009
	  read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
Packit 6c4009
					&pc_begin);
Packit 6c4009
Packit 6c4009
	  /* Take care to ignore link-once functions that were removed.
Packit 6c4009
	     In these cases, the function address will be NULL, but if
Packit 6c4009
	     the encoding is smaller than a pointer a true NULL may not
Packit 6c4009
	     be representable.  Assume 0 in the representable bits is NULL.  */
Packit 6c4009
	  mask = size_of_encoded_value (encoding);
Packit 6c4009
	  if (mask < sizeof (void *))
Packit 6c4009
	    mask = (1L << (mask << 3)) - 1;
Packit 6c4009
	  else
Packit 6c4009
	    mask = -1;
Packit 6c4009
Packit 6c4009
	  if ((pc_begin & mask) == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      fde_insert (accu, this_fde);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Set up a sorted array of pointers to FDEs for a loaded object.  We
Packit 6c4009
   count up the entries before allocating the array because it's likely to
Packit 6c4009
   be faster.  We can be called multiple times, should we have failed to
Packit 6c4009
   allocate a sorted fde array on a previous occasion.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
init_object (struct object* ob)
Packit 6c4009
{
Packit 6c4009
  struct fde_accumulator accu;
Packit 6c4009
  size_t count;
Packit 6c4009
Packit 6c4009
  count = ob->s.b.count;
Packit 6c4009
  if (count == 0)
Packit 6c4009
    {
Packit 6c4009
      if (ob->s.b.from_array)
Packit 6c4009
	{
Packit 6c4009
	  fde **p = ob->u.array;
Packit 6c4009
	  for (count = 0; *p; ++p)
Packit 6c4009
	    count += classify_object_over_fdes (ob, *p);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	count = classify_object_over_fdes (ob, ob->u.single);
Packit 6c4009
Packit 6c4009
      /* The count field we have in the main struct object is somewhat
Packit 6c4009
	 limited, but should suffice for virtually all cases.  If the
Packit 6c4009
	 counted value doesn't fit, re-write a zero.  The worst that
Packit 6c4009
	 happens is that we re-count next time -- admittedly non-trivial
Packit 6c4009
	 in that this implies some 2M fdes, but at least we function.  */
Packit 6c4009
      ob->s.b.count = count;
Packit 6c4009
      if (ob->s.b.count != count)
Packit 6c4009
	ob->s.b.count = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (!start_fde_sort (&accu, count))
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (ob->s.b.from_array)
Packit 6c4009
    {
Packit 6c4009
      fde **p;
Packit 6c4009
      for (p = ob->u.array; *p; ++p)
Packit 6c4009
	add_fdes (ob, &accu, *p);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    add_fdes (ob, &accu, ob->u.single);
Packit 6c4009
Packit 6c4009
  end_fde_sort (ob, &accu, count);
Packit 6c4009
Packit 6c4009
  /* Save the original fde pointer, since this is the key by which the
Packit 6c4009
     DSO will deregister the object.  */
Packit 6c4009
  accu.linear->orig_data = ob->u.single;
Packit 6c4009
  ob->u.sort = accu.linear;
Packit 6c4009
Packit 6c4009
  ob->s.b.sorted = 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* A linear search through a set of FDEs for the given PC.  This is
Packit 6c4009
   used when there was insufficient memory to allocate and sort an
Packit 6c4009
   array.  */
Packit 6c4009
Packit 6c4009
static fde *
Packit 6c4009
linear_search_fdes (struct object *ob, fde *this_fde, void *pc)
Packit 6c4009
{
Packit 6c4009
  struct dwarf_cie *last_cie = 0;
Packit 6c4009
  int encoding = ob->s.b.encoding;
Packit 6c4009
  _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob);
Packit 6c4009
Packit 6c4009
  for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde))
Packit 6c4009
    {
Packit 6c4009
      struct dwarf_cie *this_cie;
Packit 6c4009
      _Unwind_Ptr pc_begin, pc_range;
Packit 6c4009
Packit 6c4009
      /* Skip CIEs.  */
Packit 6c4009
      if (this_fde->CIE_delta == 0)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      if (ob->s.b.mixed_encoding)
Packit 6c4009
	{
Packit 6c4009
	  /* Determine the encoding for this FDE.  Note mixed encoded
Packit 6c4009
	     objects for later.  */
Packit 6c4009
	  this_cie = get_cie (this_fde);
Packit 6c4009
	  if (this_cie != last_cie)
Packit 6c4009
	    {
Packit 6c4009
	      last_cie = this_cie;
Packit 6c4009
	      encoding = get_cie_encoding (this_cie);
Packit 6c4009
	      base = base_from_object (encoding, ob);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (encoding == DW_EH_PE_absptr)
Packit 6c4009
	{
Packit 6c4009
	  pc_begin = get_pc_begin (this_fde, 0);
Packit 6c4009
	  pc_range = get_pc_begin (this_fde, 1);
Packit 6c4009
	  if (pc_begin == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  _Unwind_Ptr mask;
Packit 6c4009
	  const unsigned char *p;
Packit 6c4009
Packit 6c4009
	  p = read_encoded_value_with_base (encoding, base,
Packit 6c4009
					    this_fde->pc_begin, &pc_begin);
Packit 6c4009
	  read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
Packit 6c4009
Packit 6c4009
	  /* Take care to ignore link-once functions that were removed.
Packit 6c4009
	     In these cases, the function address will be NULL, but if
Packit 6c4009
	     the encoding is smaller than a pointer a true NULL may not
Packit 6c4009
	     be representable.  Assume 0 in the representable bits is NULL.  */
Packit 6c4009
	  mask = size_of_encoded_value (encoding);
Packit 6c4009
	  if (mask < sizeof (void *))
Packit 6c4009
	    mask = (1L << (mask << 3)) - 1;
Packit 6c4009
	  else
Packit 6c4009
	    mask = -1;
Packit 6c4009
Packit 6c4009
	  if ((pc_begin & mask) == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if ((_Unwind_Ptr) pc - pc_begin < pc_range)
Packit 6c4009
	return this_fde;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Binary search for an FDE containing the given PC.  Here are three
Packit 6c4009
   implementations of increasing complexity.  */
Packit 6c4009
Packit 6c4009
static fde *
Packit 6c4009
binary_search_unencoded_fdes (struct object *ob, void *pc)
Packit 6c4009
{
Packit 6c4009
  struct fde_vector *vec = ob->u.sort;
Packit 6c4009
  size_t lo, hi;
Packit 6c4009
Packit 6c4009
  for (lo = 0, hi = vec->count; lo < hi; )
Packit 6c4009
    {
Packit 6c4009
      size_t i = (lo + hi) / 2;
Packit 6c4009
      fde *f = vec->array[i];
Packit 6c4009
      void *pc_begin;
Packit 6c4009
      uaddr pc_range;
Packit 6c4009
Packit 6c4009
      pc_begin = (void *) get_pc_begin (f, 0);
Packit 6c4009
      pc_range = (uaddr) get_pc_begin (f, 1);
Packit 6c4009
Packit 6c4009
      if (pc < pc_begin)
Packit 6c4009
	hi = i;
Packit 6c4009
      else if (pc >= pc_begin + pc_range)
Packit 6c4009
	lo = i + 1;
Packit 6c4009
      else
Packit 6c4009
	return f;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static fde *
Packit 6c4009
binary_search_single_encoding_fdes (struct object *ob, void *pc)
Packit 6c4009
{
Packit 6c4009
  struct fde_vector *vec = ob->u.sort;
Packit 6c4009
  int encoding = ob->s.b.encoding;
Packit 6c4009
  _Unwind_Ptr base = base_from_object (encoding, ob);
Packit 6c4009
  size_t lo, hi;
Packit 6c4009
Packit 6c4009
  for (lo = 0, hi = vec->count; lo < hi; )
Packit 6c4009
    {
Packit 6c4009
      size_t i = (lo + hi) / 2;
Packit 6c4009
      fde *f = vec->array[i];
Packit 6c4009
      _Unwind_Ptr pc_begin, pc_range;
Packit 6c4009
      const unsigned char *p;
Packit 6c4009
Packit 6c4009
      p = read_encoded_value_with_base (encoding, base, f->pc_begin,
Packit 6c4009
					&pc_begin);
Packit 6c4009
      read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
Packit 6c4009
Packit 6c4009
      if ((_Unwind_Ptr) pc < pc_begin)
Packit 6c4009
	hi = i;
Packit 6c4009
      else if ((_Unwind_Ptr) pc >= pc_begin + pc_range)
Packit 6c4009
	lo = i + 1;
Packit 6c4009
      else
Packit 6c4009
	return f;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static fde *
Packit 6c4009
binary_search_mixed_encoding_fdes (struct object *ob, void *pc)
Packit 6c4009
{
Packit 6c4009
  struct fde_vector *vec = ob->u.sort;
Packit 6c4009
  size_t lo, hi;
Packit 6c4009
Packit 6c4009
  for (lo = 0, hi = vec->count; lo < hi; )
Packit 6c4009
    {
Packit 6c4009
      size_t i = (lo + hi) / 2;
Packit 6c4009
      fde *f = vec->array[i];
Packit 6c4009
      _Unwind_Ptr pc_begin, pc_range;
Packit 6c4009
      const unsigned char *p;
Packit 6c4009
      int encoding;
Packit 6c4009
Packit 6c4009
      encoding = get_fde_encoding (f);
Packit 6c4009
      p = read_encoded_value_with_base (encoding,
Packit 6c4009
					base_from_object (encoding, ob),
Packit 6c4009
					f->pc_begin, &pc_begin);
Packit 6c4009
      read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
Packit 6c4009
Packit 6c4009
      if ((_Unwind_Ptr) pc < pc_begin)
Packit 6c4009
	hi = i;
Packit 6c4009
      else if ((_Unwind_Ptr) pc >= pc_begin + pc_range)
Packit 6c4009
	lo = i + 1;
Packit 6c4009
      else
Packit 6c4009
	return f;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static fde *
Packit 6c4009
search_object (struct object* ob, void *pc)
Packit 6c4009
{
Packit 6c4009
  /* If the data hasn't been sorted, try to do this now.  We may have
Packit 6c4009
     more memory available than last time we tried.  */
Packit 6c4009
  if (! ob->s.b.sorted)
Packit 6c4009
    {
Packit 6c4009
      init_object (ob);
Packit 6c4009
Packit 6c4009
      /* Despite the above comment, the normal reason to get here is
Packit 6c4009
	 that we've not processed this object before.  A quick range
Packit 6c4009
	 check is in order.  */
Packit 6c4009
      if (pc < ob->pc_begin)
Packit 6c4009
	return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (ob->s.b.sorted)
Packit 6c4009
    {
Packit 6c4009
      if (ob->s.b.mixed_encoding)
Packit 6c4009
	return binary_search_mixed_encoding_fdes (ob, pc);
Packit 6c4009
      else if (ob->s.b.encoding == DW_EH_PE_absptr)
Packit 6c4009
	return binary_search_unencoded_fdes (ob, pc);
Packit 6c4009
      else
Packit 6c4009
	return binary_search_single_encoding_fdes (ob, pc);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Long slow labourious linear search, cos we've no memory.  */
Packit 6c4009
      if (ob->s.b.from_array)
Packit 6c4009
	{
Packit 6c4009
	  fde **p;
Packit 6c4009
	  for (p = ob->u.array; *p ; p++)
Packit 6c4009
	    {
Packit 6c4009
	      fde *f = linear_search_fdes (ob, *p, pc);
Packit 6c4009
	      if (f)
Packit 6c4009
		return f;
Packit 6c4009
	    }
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	return linear_search_fdes (ob, ob->u.single, pc);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
fde *
Packit 6c4009
_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
Packit 6c4009
{
Packit 6c4009
  struct object *ob;
Packit 6c4009
  fde *f = NULL;
Packit 6c4009
Packit 6c4009
  init_object_mutex_once ();
Packit 6c4009
  __gthread_mutex_lock (&object_mutex);
Packit 6c4009
Packit 6c4009
  /* Linear search through the classified objects, to find the one
Packit 6c4009
     containing the pc.  Note that pc_begin is sorted descending, and
Packit 6c4009
     we expect objects to be non-overlapping.  */
Packit 6c4009
  for (ob = seen_objects; ob; ob = ob->next)
Packit 6c4009
    if (pc >= ob->pc_begin)
Packit 6c4009
      {
Packit 6c4009
	f = search_object (ob, pc);
Packit 6c4009
	if (f)
Packit 6c4009
	  goto fini;
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  /* Classify and search the objects we've not yet processed.  */
Packit 6c4009
  while ((ob = unseen_objects))
Packit 6c4009
    {
Packit 6c4009
      struct object **p;
Packit 6c4009
Packit 6c4009
      unseen_objects = ob->next;
Packit 6c4009
      f = search_object (ob, pc);
Packit 6c4009
Packit 6c4009
      /* Insert the object into the classified list.  */
Packit 6c4009
      for (p = &seen_objects; *p ; p = &(*p)->next)
Packit 6c4009
	if ((*p)->pc_begin < ob->pc_begin)
Packit 6c4009
	  break;
Packit 6c4009
      ob->next = *p;
Packit 6c4009
      *p = ob;
Packit 6c4009
Packit 6c4009
      if (f)
Packit 6c4009
	goto fini;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 fini:
Packit 6c4009
  __gthread_mutex_unlock (&object_mutex);
Packit 6c4009
Packit 6c4009
  if (f)
Packit 6c4009
    {
Packit 6c4009
      int encoding;
Packit 6c4009
      _Unwind_Ptr func;
Packit 6c4009
Packit 6c4009
      bases->tbase = ob->tbase;
Packit 6c4009
      bases->dbase = ob->dbase;
Packit 6c4009
Packit 6c4009
      encoding = ob->s.b.encoding;
Packit 6c4009
      if (ob->s.b.mixed_encoding)
Packit 6c4009
	encoding = get_fde_encoding (f);
Packit 6c4009
      read_encoded_value_with_base (encoding, base_from_object (encoding, ob),
Packit 6c4009
				    f->pc_begin, &func);
Packit 6c4009
      bases->func = (void *) func;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return f;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif