/* 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.
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
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 = ▮
+ 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, ®);
- 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, ®);
- 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, ®);
- p = decode_uleb128 (p, ®2);
- state->s.saved[reg] = REG_SAVED_REG;
- state->s.reg_or_offset[reg] = reg2;
- }
- break;
-
- case DW_CFA_def_cfa:
- p = decode_uleb128 (p, ®);
- 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, ®);
- 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
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)
*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 */
+