OSDN Git Service

2000-07-11 Zack Weinberg <zack@wolery.cumb.org>
[pf3gnuchains/gcc-fork.git] / gcc / frame.c
index 1fb29e4..399df57 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines needed for unwinding stack frames for exception handling.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
    Contributed by Jason Merrill <jason@cygnus.com>.
 
 This file is part of GNU CC.
@@ -10,6 +10,15 @@ it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
 GNU CC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -20,510 +29,243 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* As a special exception, if you link this library with other files,
-   some of which are compiled with GCC, to produce an executable,
-   this library does not by itself cause the resulting executable
-   to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
-/* It is incorrect to include config.h here, because this file is being
-   compiled for the target, and hence definitions concerning only the host
-   do not apply.  */
-
-#include "tconfig.h"
-#include "defaults.h"
-
-#ifdef DWARF2_UNWIND_INFO
-#include "gansidecl.h"
-#include "dwarf2.h"
-#include "frame.h"
-#include <stddef.h>
-
-/* Don't use `fancy_abort' here even if config.h says to use it.  */
-#ifdef abort
-#undef abort
-#endif
-
-/* Some types used by the DWARF 2 spec.  */
-
-typedef          int  sword __attribute__ ((mode (SI)));
-typedef unsigned int  uword __attribute__ ((mode (SI)));
-typedef unsigned int  uaddr __attribute__ ((mode (pointer)));
-typedef          int  saddr __attribute__ ((mode (pointer)));
-typedef unsigned char ubyte;
-
-/* The first few fields of a CIE.  The CIE_id field is 0xffffffff for a CIE,
-   to distinguish it from a valid FDE.  FDEs are aligned to an addressing
-   unit boundary, but the fields within are unaligned.  */
-
-struct dwarf_cie {
-  uword length;
-  sword CIE_id;
-  ubyte version;
-  char augmentation[0];
-} __attribute__ ((packed, aligned (__alignof__ (void *))));
-
-/* The first few fields of an FDE.  */
-
-struct dwarf_fde {
-  uword length;
-  sword CIE_delta;
-  void* pc_begin;
-  uaddr pc_range;
-} __attribute__ ((packed, aligned (__alignof__ (void *))));
-
-typedef struct dwarf_fde fde;
-
-/* The representation for an "object" to be searched for frame unwind info.
-   For targets with named sections, one object is an executable or shared
-   library; for other targets, one object is one translation unit.  */
-
-struct object {
-  void *pc_begin;
-  void *pc_end;
-  fde *fde_begin;
-  fde ** fde_array;
-  size_t count;
-  struct object *next;
-};
-
-static struct object *objects;
-
-/* The information we care about from a CIE.  */
-
-struct cie_info {
-  char *augmentation;
-  void *eh_ptr;
-  int code_align;
-  int data_align;
-  unsigned ra_regno;
-};
-
-/* The current unwind state, plus a saved copy for DW_CFA_remember_state.  */
-
-struct frame_state_internal
-{
-  struct frame_state s;
-  struct frame_state_internal *saved_state;
-};
-\f  
-/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
-   by R, and return the new value of BUF.  */
-
-static void *
-decode_uleb128 (unsigned char *buf, unsigned *r)
-{
-  unsigned shift = 0;
-  unsigned result = 0;
-
-  while (1)
-    {
-      unsigned byte = *buf++;
-      result |= (byte & 0x7f) << shift;
-      if ((byte & 0x80) == 0)
-       break;
-      shift += 7;
-    }
-  *r = result;
-  return buf;
-}
-
-/* Decode the signed LEB128 constant at BUF into the variable pointed to
-   by R, and return the new value of BUF.  */
-
-static void *
-decode_sleb128 (unsigned char *buf, int *r)
+/* Sorting an array of FDEs by address.
+   (Ideally we would have the linker sort the FDEs so we don't have to do
+   it at run time. But the linkers are not yet prepared for this.)  */
+
+/* This is a special mix of insertion sort and heap sort, optimized for
+   the data sets that actually occur. They look like
+   101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
+   I.e. a linearly increasing sequence (coming from functions in the text
+   section), with additionally a few unordered elements (coming from functions
+   in gnu_linkonce sections) whose values are higher than the values in the
+   surrounding linear sequence (but not necessarily higher than the values
+   at the end of the linear sequence!).
+   The worst-case total run time is O(N) + O(n log (n)), where N is the
+   total number of FDEs and n is the number of erratic ones.  */
+
+typedef struct fde_vector
 {
-  unsigned shift = 0;
-  unsigned result = 0;
-  unsigned byte;
-
-  while (1)
-    {
-      byte = *buf++;
-      result |= (byte & 0x7f) << shift;
-      shift += 7;
-      if ((byte & 0x80) == 0)
-       break;
-    }
-  if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
-    result |= - (1 << shift);
-
-  *r = result;
-  return buf;
-}
+  fde **array;
+  size_t count;
+} fde_vector;
 
-/* Read unaligned data from the instruction buffer.  */
-
-union unaligned {
-  void *p;
-  unsigned b2 __attribute__ ((mode (HI)));
-  unsigned b4 __attribute__ ((mode (SI)));
-  unsigned b8 __attribute__ ((mode (DI)));
-} __attribute__ ((packed));
-static inline void *
-read_pointer (void *p)
-{ union unaligned *up = p; return up->p; }
-static inline unsigned
-read_1byte (void *p)
-{ return *(unsigned char *)p; }
-static inline unsigned
-read_2byte (void *p)
-{ union unaligned *up = p; return up->b2; }
-static inline unsigned
-read_4byte (void *p)
-{ union unaligned *up = p; return up->b4; }
-static inline unsigned long
-read_8byte (void *p)
-{ union unaligned *up = p; return up->b8; }
-\f
-/* Ordering function for FDEs.  Functions can't overlap, so we just compare
-   their starting addresses.  */
-
-static inline saddr
-fde_compare (fde *x, fde *y)
+typedef struct fde_accumulator
 {
-  return (saddr)x->pc_begin - (saddr)y->pc_begin;
-}
-
-/* Return the address of the FDE after P.  */
+  fde_vector linear;
+  fde_vector erratic;
+} fde_accumulator;
 
-static inline fde *
-next_fde (fde *p)
+static inline int
+start_fde_sort (fde_accumulator *accu, size_t count)
 {
-  return (fde *)(((char *)p) + p->length + sizeof (p->length));
+  accu->linear.array = count ? (fde **) malloc (sizeof (fde *) * count) : NULL;
+  accu->erratic.array = accu->linear.array ?
+      (fde **) malloc (sizeof (fde *) * count) : NULL;
+  accu->linear.count = 0;
+  accu->erratic.count = 0;
+  
+  return accu->linear.array != NULL;
 }
 
-/* One iteration of an insertion sort, for adding new FDEs to the array.
-   Usually the new FDE will go in at the end, so we can expect close to
-   O(n) performance.  If this turns out to be overly optimistic, we can have
-   the linker sort the FDEs so we don't have to do it at run time.  */
-
-static void
-fde_insert (fde **array, size_t i, fde *this_fde)
+static inline void
+fde_insert (fde_accumulator *accu, fde *this_fde)
 {
-  array[i] = this_fde;
-
-  for (; i > 0 && fde_compare (array[i], array[i-1]) < 0; --i)
-    {
-      this_fde = array[i];
-      array[i] = array[i-1];
-      array[i-1] = this_fde;
-    }
+  if (accu->linear.array)
+    accu->linear.array[accu->linear.count++] = this_fde;
 }
 
-static size_t
-count_fdes (fde *this_fde)
+/* Split LINEAR into a linear sequence with low values and an erratic
+   sequence with high values, put the linear one (of longest possible
+   length) into LINEAR and the erratic one into ERRATIC. This is O(N).
+   
+   Because the longest linear sequence we are trying to locate within the
+   incoming LINEAR array can be interspersed with (high valued) erratic
+   entries.  We construct a chain indicating the sequenced entries.
+   To avoid having to allocate this chain, we overlay it onto the space of
+   the ERRATIC array during construction.  A final pass iterates over the
+   chain to determine what should be placed in the ERRATIC array, and
+   what is the linear sequence.  This overlay is safe from aliasing.  */
+static inline void
+fde_split (fde_vector *linear, fde_vector *erratic)
 {
-  size_t count;
-
-  for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
+  static fde *marker;
+  size_t count = linear->count;
+  fde **chain_end = &marker;
+  size_t i, j, k;
+
+  /* This should optimize out, but it is wise to make sure this assumption
+     is correct. Should these have different sizes, we cannot cast between
+     them and the overlaying onto ERRATIC will not work.  */
+  if (sizeof (fde *) != sizeof (fde **))
+    abort ();
+  
+  for (i = 0; i < count; i++)
     {
-      /* Skip CIEs and linked once FDE entries.  */
-      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
-       continue;
-
-      ++count;
+      fde **probe;
+      
+      for (probe = chain_end;
+           probe != &marker && fde_compare (linear->array[i], *probe) < 0;
+           probe = chain_end)
+        {
+          chain_end = (fde **)erratic->array[probe - linear->array];
+          erratic->array[probe - linear->array] = NULL;
+        }
+      erratic->array[i] = (fde *)chain_end;
+      chain_end = &linear->array[i];
     }
 
-  return count;
+  /* Each entry in LINEAR which is part of the linear sequence we have
+     discovered will correspond to a non-NULL entry in the chain we built in
+     the ERRATIC array.  */
+  for (i = j = k = 0; i < count; i++)
+    if (erratic->array[i])
+      linear->array[j++] = linear->array[i];
+    else
+      erratic->array[k++] = linear->array[i];
+  linear->count = j;
+  erratic->count = k;
 }
 
-static void
-add_fdes (fde *this_fde, fde **array, size_t *i_ptr,
-         void **beg_ptr, void **end_ptr)
+/* This is O(n log(n)).  BSD/OS defines heapsort in stdlib.h, so we must
+   use a name that does not conflict.  */
+static inline void
+frame_heapsort (fde_vector *erratic)
 {
-  size_t i = *i_ptr;
-  void *pc_begin = *beg_ptr;
-  void *pc_end = *end_ptr;
-
-  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+  /* For a description of this algorithm, see:
+     Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed.,
+     p. 60-61. */
+  fde ** a = erratic->array;
+  /* A portion of the array is called a "heap" if for all i>=0:
+     If i and 2i+1 are valid indices, then a[i] >= a[2i+1].
+     If i and 2i+2 are valid indices, then a[i] >= a[2i+2]. */
+#define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0)
+  size_t n = erratic->count;
+  size_t m = n;
+  size_t i;
+
+  while (m > 0)
     {
-      /* Skip CIEs and linked once FDE entries.  */
-      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
-       continue;
-
-      fde_insert (array, i++, this_fde);
-
-      if (this_fde->pc_begin < pc_begin)
-       pc_begin = this_fde->pc_begin;
-      if (this_fde->pc_begin + this_fde->pc_range > pc_end)
-       pc_end = this_fde->pc_begin + this_fde->pc_range;
+      /* Invariant: a[m..n-1] is a heap. */
+      m--;
+      for (i = m; 2*i+1 < n; )
+        {
+          if (2*i+2 < n
+              && fde_compare (a[2*i+2], a[2*i+1]) > 0
+              && fde_compare (a[2*i+2], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+2]);
+              i = 2*i+2;
+            }
+          else if (fde_compare (a[2*i+1], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+1]);
+              i = 2*i+1;
+            }
+          else
+            break;
+        }
     }
-
-  *i_ptr = i;
-  *beg_ptr = pc_begin;
-  *end_ptr = pc_end;
-}
-
-/* Set up a sorted array of pointers to FDEs for a loaded object.  We
-   count up the entries before allocating the array because it's likely to
-   be faster.  */
-
-static void
-frame_init (struct object* ob)
-{
-  fde *this_fde;
-  size_t count;
-  fde **array;
-  void *pc_begin, *pc_end;
-
-  if (ob->fde_array)
+  while (n > 1)
     {
-      fde **p = ob->fde_array;
-      for (count = 0; *p; ++p)
-       count += count_fdes (*p);
+      /* Invariant: a[0..n-1] is a heap. */
+      n--;
+      SWAP (a[0], a[n]);
+      for (i = 0; 2*i+1 < n; )
+        {
+          if (2*i+2 < n
+              && fde_compare (a[2*i+2], a[2*i+1]) > 0
+              && fde_compare (a[2*i+2], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+2]);
+              i = 2*i+2;
+            }
+          else if (fde_compare (a[2*i+1], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+1]);
+              i = 2*i+1;
+            }
+          else
+            break;
+        }
     }
-  else
-    count = count_fdes (ob->fde_begin);
-
-  ob->count = count;
-  array = (fde **) malloc (sizeof (fde *) * count);
-
-  pc_begin = (void*)(uaddr)-1;
-  pc_end = 0;
-  count = 0;
-
-  if (ob->fde_array)
-    {
-      fde **p = ob->fde_array;
-      for (; *p; ++p)
-       add_fdes (*p, array, &count, &pc_begin, &pc_end);
-    }
-  else
-    add_fdes (ob->fde_begin, array, &count, &pc_begin, &pc_end);
-
-  ob->fde_array = array;
-  ob->pc_begin = pc_begin;
-  ob->pc_end = pc_end;
+#undef SWAP
 }
 
-/* Return a pointer to the FDE for the function containing PC.  */
-
-static fde *
-find_fde (void *pc)
+/* Merge V1 and V2, both sorted, and put the result into V1. */
+static void
+fde_merge (fde_vector *v1, const fde_vector *v2)
 {
-  struct object *ob;
-  size_t lo, hi;
+  size_t i1, i2;
+  fde * fde2;
 
-  for (ob = objects; ob; ob = ob->next)
+  i2 = v2->count;
+  if (i2 > 0)
     {
-      if (ob->pc_begin == 0)
-       frame_init (ob);
-      if (pc >= ob->pc_begin && pc < ob->pc_end)
-       break;
+      i1 = v1->count;
+      do {
+        i2--;
+        fde2 = v2->array[i2];
+        while (i1 > 0 && fde_compare (v1->array[i1-1], fde2) > 0)
+          {
+            v1->array[i1+i2] = v1->array[i1-1];
+            i1--;
+          }
+        v1->array[i1+i2] = fde2;
+      } while (i2 > 0);
+      v1->count += v2->count;
     }
-
-  if (ob == 0)
-    return 0;
-
-  /* Standard binary search algorithm.  */
-  for (lo = 0, hi = ob->count; lo < hi; )
-    {
-      size_t i = (lo + hi) / 2;
-      fde *f = ob->fde_array[i];
-
-      if (pc < f->pc_begin)
-       hi = i;
-      else if (pc > f->pc_begin + f->pc_range)
-       lo = i + 1;
-      else
-       return f;
-    }
-
-  return 0;
-}
-\f
-static inline struct dwarf_cie *
-get_cie (fde *f)
-{
-  return ((void *)&f->CIE_delta) - f->CIE_delta;
 }
 
-/* Extract any interesting information from the CIE for the translation
-   unit F belongs to.  */
-
-static void *
-extract_cie_info (fde *f, struct cie_info *c)
+static fde **
+end_fde_sort (fde_accumulator *accu, size_t count)
 {
-  void *p;
-  int i;
-
-  c->augmentation = get_cie (f)->augmentation;
-
-  if (strcmp (c->augmentation, "") != 0
-      && strcmp (c->augmentation, "eh") != 0
-      && c->augmentation[0] != 'z')
-    return 0;
-
-  p = c->augmentation + strlen (c->augmentation) + 1;
-
-  if (strcmp (c->augmentation, "eh") == 0)
+  if (accu->linear.array && accu->linear.count != count)
+    abort ();
+  
+  if (accu->erratic.array)
     {
-      c->eh_ptr = read_pointer (p);
-      p += sizeof (void *);
+      fde_split (&accu->linear, &accu->erratic);
+      if (accu->linear.count + accu->erratic.count != count)
+       abort ();
+      frame_heapsort (&accu->erratic);
+      fde_merge (&accu->linear, &accu->erratic);
+      free (accu->erratic.array);
     }
   else
-    c->eh_ptr = 0;
-
-  p = decode_uleb128 (p, &c->code_align);
-  p = decode_sleb128 (p, &c->data_align);
-  c->ra_regno = *(unsigned char *)p++;
-
-  /* If the augmentation starts with 'z', we now see the length of the
-     augmentation fields.  */
-  if (c->augmentation[0] == 'z')
     {
-      p = decode_uleb128 (p, &i);
-      p += i;
+      /* We've not managed to malloc an erratic array, so heap sort in the
+         linear one.  */
+      frame_heapsort (&accu->linear);
     }
-
-  return p;
+  return accu->linear.array;
 }
 
-/* Decode one instruction's worth of of DWARF 2 call frame information.
-   Used by __frame_state_for.  Takes pointers P to the instruction to
-   decode, STATE to the current register unwind information, INFO to the
-   current CIE information, and PC to the current PC value.  Returns a
-   pointer to the next instruction.  */
-
-static void *
-execute_cfa_insn (void *p, struct frame_state_internal *state,
-                 struct cie_info *info, void **pc)
-{
-  unsigned insn = *(unsigned char *)p++;
-  unsigned reg;
-  int offset;
-
-  if (insn & DW_CFA_advance_loc)
-    *pc += ((insn & 0x3f) * info->code_align);
-  else if (insn & DW_CFA_offset)
-    {
-      reg = (insn & 0x3f);
-      p = decode_uleb128 (p, &offset);
-      offset *= info->data_align;
-      state->s.saved[reg] = REG_SAVED_OFFSET;
-      state->s.reg_or_offset[reg] = offset;
-    }
-  else if (insn & DW_CFA_restore)
-    {
-      reg = (insn & 0x3f);
-      state->s.saved[reg] = REG_UNSAVED;
-    }
-  else switch (insn)
-    {
-    case DW_CFA_set_loc:
-      *pc = read_pointer (p);
-      p += sizeof (void *);
-      break;
-    case DW_CFA_advance_loc1:
-      *pc += read_1byte (p);
-      p += 1;
-      break;
-    case DW_CFA_advance_loc2:
-      *pc += read_2byte (p);
-      p += 2;
-      break;
-    case DW_CFA_advance_loc4:
-      *pc += read_4byte (p);
-      p += 4;
-      break;
-
-    case DW_CFA_offset_extended:
-      p = decode_uleb128 (p, &reg);
-      p = decode_uleb128 (p, &offset);
-      offset *= info->data_align;
-      state->s.saved[reg] = REG_SAVED_OFFSET;
-      state->s.reg_or_offset[reg] = offset;
-      break;
-    case DW_CFA_restore_extended:
-      p = decode_uleb128 (p, &reg);
-      state->s.saved[reg] = REG_UNSAVED;
-      break;
-
-    case DW_CFA_undefined:
-    case DW_CFA_same_value:
-    case DW_CFA_nop:
-      break;
-
-    case DW_CFA_register:
-      {
-       unsigned reg2;
-       p = decode_uleb128 (p, &reg);
-       p = decode_uleb128 (p, &reg2);
-       state->s.saved[reg] = REG_SAVED_REG;
-       state->s.reg_or_offset[reg] = reg2;
-      }
-      break;
-
-    case DW_CFA_def_cfa:
-      p = decode_uleb128 (p, &reg);
-      p = decode_uleb128 (p, &offset);
-      state->s.cfa_reg = reg;
-      state->s.cfa_offset = offset;
-      break;
-    case DW_CFA_def_cfa_register:
-      p = decode_uleb128 (p, &reg);
-      state->s.cfa_reg = reg;
-      break;
-    case DW_CFA_def_cfa_offset:
-      p = decode_uleb128 (p, &offset);
-      state->s.cfa_offset = offset;
-      break;
-      
-    case DW_CFA_remember_state:
-      {
-       struct frame_state_internal *save =
-         (struct frame_state_internal *)
-         malloc (sizeof (struct frame_state_internal));
-       memcpy (save, state, sizeof (struct frame_state_internal));
-       state->saved_state = save;
-      }
-      break;
-    case DW_CFA_restore_state:
-      {
-       struct frame_state_internal *save = state->saved_state;
-       memcpy (state, save, sizeof (struct frame_state_internal));
-       free (save);
-      }
-      break;
-
-      /* FIXME: Hardcoded for SPARC register window configuration.  */
-    case DW_CFA_GNU_window_save:
-      for (reg = 16; reg < 32; ++reg)
-       {
-         state->s.saved[reg] = REG_SAVED_OFFSET;
-         state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
-       }
-      break;
-
-    case DW_CFA_GNU_args_size:
-      p = decode_uleb128 (p, &offset);
-      state->s.args_size = offset;
-      break;
-
-    default:
-      abort ();
-    }
-  return p;
-}
-\f
 /* Called from crtbegin.o to register the unwind info for an object.  */
 
 void
-__register_frame (void *begin)
+__register_frame_info (void *begin, struct object *ob)
 {
-  struct object *ob = (struct object *) malloc (sizeof (struct object));
-
   ob->fde_begin = begin;
 
   ob->pc_begin = ob->pc_end = 0;
   ob->fde_array = 0;
   ob->count = 0;
 
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
   ob->next = objects;
   objects = ob;
+
+  __gthread_mutex_unlock (&object_mutex);
+}
+
+void
+__register_frame (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+  __register_frame_info (begin, ob);                       
 }
 
 /* Similar, but BEGIN is actually a pointer to a table of unwind entries
@@ -531,27 +273,41 @@ __register_frame (void *begin)
    collect2.  */
 
 void
-__register_frame_table (void *begin)
+__register_frame_info_table (void *begin, struct object *ob)
 {
-  struct object *ob = (struct object *) malloc (sizeof (struct object));
-
   ob->fde_begin = begin;
   ob->fde_array = begin;
 
   ob->pc_begin = ob->pc_end = 0;
   ob->count = 0;
 
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
   ob->next = objects;
   objects = ob;
-}
 
-/* Called from crtend.o to deregister the unwind info for an object.  */
+  __gthread_mutex_unlock (&object_mutex);
+}
 
 void
-__deregister_frame (void *begin)
+__register_frame_table (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+  __register_frame_info_table (begin, ob);
+}
+
+/* Called from crtbegin.o to deregister the unwind info for an object.  */
+
+void *
+__deregister_frame_info (void *begin)
 {
-  struct object **p = &objects;
+  struct object **p;
+
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
 
+  p = &objects;
   while (*p)
     {
       if ((*p)->fde_begin == begin)
@@ -560,62 +316,22 @@ __deregister_frame (void *begin)
          *p = (*p)->next;
 
          /* If we've run init_frame for this object, free the FDE array.  */
-         if (ob->pc_begin)
+         if (ob->fde_array && ob->fde_array != begin)
            free (ob->fde_array);
-         free (ob);
 
-         return;
+         __gthread_mutex_unlock (&object_mutex);
+         return (void *) ob;
        }
       p = &((*p)->next);
     }
+
+  __gthread_mutex_unlock (&object_mutex);
   abort ();
 }
 
-/* Called from __throw to find the registers to restore for a given
-   PC_TARGET.  The caller should allocate a local variable of `struct
-   frame_state' (declared in frame.h) and pass its address to STATE_IN.  */
-
-struct frame_state *
-__frame_state_for (void *pc_target, struct frame_state *state_in)
+void
+__deregister_frame (void *begin)
 {
-  fde *f;
-  void *insn, *end, *pc;
-  struct cie_info info;
-  struct frame_state_internal state;
-
-  f = find_fde (pc_target);
-  if (f == 0)
-    return 0;
-
-  insn = extract_cie_info (f, &info);
-  if (insn == 0)
-    return 0;
-
-  memset (&state, 0, sizeof (state));
-  state.s.retaddr_column = info.ra_regno;
-  state.s.eh_ptr = info.eh_ptr;
-
-  /* First decode all the insns in the CIE.  */
-  end = next_fde ((fde*) get_cie (f));
-  while (insn < end)
-    insn = execute_cfa_insn (insn, &state, &info, 0);
-
-  insn = ((fde *)f) + 1;
-
-  if (info.augmentation[0] == 'z')
-    {
-      int i;
-      insn = decode_uleb128 (insn, &i);
-      insn += i;
-    }
-
-  /* Then the insns in the FDE up to our target PC.  */
-  end = next_fde (f);
-  pc = f->pc_begin;
-  while (insn < end && pc <= pc_target)
-    insn = execute_cfa_insn (insn, &state, &info, &pc);
-
-  memcpy (state_in, &state.s, sizeof (state.s));
-  return state_in;
+  free (__deregister_frame_info (begin));
 }
-#endif /* DWARF2_UNWIND_INFO */
+