OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [unwind-dw2-fde-glibc.c] - Blame information for rev 858

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 julius
/* Copyright (C) 2001, 2002, 2003, 2004, 2005 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 2, 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
   You should have received a copy of the GNU General Public License
17
   along with GCC; see the file COPYING.  If not, write to
18
   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19
   Boston, MA 02110-1301, USA.  */
20
 
21
/* As a special exception, if you link this library with other files,
22
   some of which are compiled with GCC, to produce an executable,
23
   this library does not by itself cause the resulting executable
24
   to be covered by the GNU General Public License.
25
   This exception does not however invalidate any other reasons why
26
   the executable file might be covered by the GNU General Public License.  */
27
 
28
/* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
29
   segment and dl_iterate_phdr to avoid register/deregister calls at
30
   DSO load/unload.  */
31
 
32
#ifndef _GNU_SOURCE
33
#define _GNU_SOURCE 1
34
#endif
35
 
36
#include "tconfig.h"
37
#include "tsystem.h"
38
#ifndef inhibit_libc
39
#include <link.h>
40
#endif
41
#include "coretypes.h"
42
#include "tm.h"
43
#include "dwarf2.h"
44
#include "unwind.h"
45
#define NO_BASE_OF_ENCODED_VALUE
46
#include "unwind-pe.h"
47
#include "unwind-dw2-fde.h"
48
#include "unwind-compat.h"
49
#include "gthr.h"
50
 
51
#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
52
    && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
53
        || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
54
 
55
#ifndef __RELOC_POINTER
56
# define __RELOC_POINTER(ptr, base) ((ptr) + (base))
57
#endif
58
 
59
static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases);
60
 
61
#define _Unwind_Find_FDE _Unwind_Find_registered_FDE
62
#include "unwind-dw2-fde.c"
63
#undef _Unwind_Find_FDE
64
 
65
#ifndef PT_GNU_EH_FRAME
66
#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
67
#endif
68
 
69
struct unw_eh_callback_data
70
{
71
  _Unwind_Ptr pc;
72
  void *tbase;
73
  void *dbase;
74
  void *func;
75
  const fde *ret;
76
  int check_cache;
77
};
78
 
79
struct unw_eh_frame_hdr
80
{
81
  unsigned char version;
82
  unsigned char eh_frame_ptr_enc;
83
  unsigned char fde_count_enc;
84
  unsigned char table_enc;
85
};
86
 
87
#define FRAME_HDR_CACHE_SIZE 8
88
 
89
static struct frame_hdr_cache_element
90
{
91
  _Unwind_Ptr pc_low;
92
  _Unwind_Ptr pc_high;
93
  _Unwind_Ptr load_base;
94
  const ElfW(Phdr) *p_eh_frame_hdr;
95
  const ElfW(Phdr) *p_dynamic;
96
  struct frame_hdr_cache_element *link;
97
} frame_hdr_cache[FRAME_HDR_CACHE_SIZE];
98
 
99
static struct frame_hdr_cache_element *frame_hdr_cache_head;
100
 
101
/* Like base_of_encoded_value, but take the base from a struct
102
   unw_eh_callback_data instead of an _Unwind_Context.  */
103
 
104
static _Unwind_Ptr
105
base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
106
{
107
  if (encoding == DW_EH_PE_omit)
108
    return 0;
109
 
110
  switch (encoding & 0x70)
111
    {
112
    case DW_EH_PE_absptr:
113
    case DW_EH_PE_pcrel:
114
    case DW_EH_PE_aligned:
115
      return 0;
116
 
117
    case DW_EH_PE_textrel:
118
      return (_Unwind_Ptr) data->tbase;
119
    case DW_EH_PE_datarel:
120
      return (_Unwind_Ptr) data->dbase;
121
    default:
122
      gcc_unreachable ();
123
    }
124
}
125
 
126
static int
127
_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
128
{
129
  struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
130
  const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
131
  long n, match;
132
#ifdef __FRV_FDPIC__
133
  struct elf32_fdpic_loadaddr load_base;
134
#else
135
  _Unwind_Ptr load_base;
136
#endif
137
  const unsigned char *p;
138
  const struct unw_eh_frame_hdr *hdr;
139
  _Unwind_Ptr eh_frame;
140
  struct object ob;
141
 
142
  struct ext_dl_phdr_info
143
    {
144
      ElfW(Addr) dlpi_addr;
145
      const char *dlpi_name;
146
      const ElfW(Phdr) *dlpi_phdr;
147
      ElfW(Half) dlpi_phnum;
148
      unsigned long long int dlpi_adds;
149
      unsigned long long int dlpi_subs;
150
    };
151
 
152
  match = 0;
153
  phdr = info->dlpi_phdr;
154
  load_base = info->dlpi_addr;
155
  p_eh_frame_hdr = NULL;
156
  p_dynamic = NULL;
157
 
158
  struct frame_hdr_cache_element *prev_cache_entry = NULL,
159
    *last_cache_entry = NULL;
160
 
161
  if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info))
162
    {
163
      static unsigned long long adds = -1ULL, subs;
164
      struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info;
165
 
166
      /* We use a least recently used cache replacement policy.  Also,
167
         the most recently used cache entries are placed at the head
168
         of the search chain.  */
169
 
170
      if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs)
171
        {
172
          /* Find data->pc in shared library cache.
173
             Set load_base, p_eh_frame_hdr and p_dynamic
174
             plus match from the cache and goto
175
             "Read .eh_frame_hdr header." below.  */
176
 
177
          struct frame_hdr_cache_element *cache_entry;
178
 
179
          for (cache_entry = frame_hdr_cache_head;
180
               cache_entry;
181
               cache_entry = cache_entry->link)
182
            {
183
              if (data->pc >= cache_entry->pc_low
184
                  && data->pc < cache_entry->pc_high)
185
                {
186
                  load_base = cache_entry->load_base;
187
                  p_eh_frame_hdr = cache_entry->p_eh_frame_hdr;
188
                  p_dynamic = cache_entry->p_dynamic;
189
 
190
                  /* And move the entry we're using to the head.  */
191
                  if (cache_entry != frame_hdr_cache_head)
192
                    {
193
                      prev_cache_entry->link = cache_entry->link;
194
                      cache_entry->link = frame_hdr_cache_head;
195
                      frame_hdr_cache_head = cache_entry;
196
                    }
197
                  goto found;
198
                }
199
 
200
              last_cache_entry = cache_entry;
201
              /* Exit early if we found an unused entry.  */
202
              if ((cache_entry->pc_low | cache_entry->pc_high) == 0)
203
                break;
204
              if (cache_entry->link != NULL)
205
                prev_cache_entry = cache_entry;
206
            }
207
        }
208
      else
209
        {
210
          adds = einfo->dlpi_adds;
211
          subs = einfo->dlpi_subs;
212
          /* Initialize the cache.  Create a chain of cache entries,
213
             with the final one terminated by a NULL link.  */
214
          int i;
215
          for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++)
216
            {
217
              frame_hdr_cache[i].pc_low = 0;
218
              frame_hdr_cache[i].pc_high = 0;
219
              frame_hdr_cache[i].link = &frame_hdr_cache[i+1];
220
            }
221
          frame_hdr_cache[i-1].link = NULL;
222
          frame_hdr_cache_head = &frame_hdr_cache[0];
223
          data->check_cache = 0;
224
        }
225
    }
226
 
227
  /* Make sure struct dl_phdr_info is at least as big as we need.  */
228
  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
229
             + sizeof (info->dlpi_phnum))
230
    return -1;
231
 
232
  _Unwind_Ptr pc_low = 0, pc_high = 0;
233
 
234
  /* See if PC falls into one of the loaded segments.  Find the eh_frame
235
     segment at the same time.  */
236
  for (n = info->dlpi_phnum; --n >= 0; phdr++)
237
    {
238
      if (phdr->p_type == PT_LOAD)
239
        {
240
          _Unwind_Ptr vaddr = (_Unwind_Ptr)
241
            __RELOC_POINTER (phdr->p_vaddr, load_base);
242
          if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
243
            {
244
              match = 1;
245
              pc_low = vaddr;
246
              pc_high =  vaddr + phdr->p_memsz;
247
            }
248
        }
249
      else if (phdr->p_type == PT_GNU_EH_FRAME)
250
        p_eh_frame_hdr = phdr;
251
      else if (phdr->p_type == PT_DYNAMIC)
252
        p_dynamic = phdr;
253
    }
254
 
255
  if (!match)
256
    return 0;
257
 
258
  if (size >= sizeof (struct ext_dl_phdr_info))
259
    {
260
      /* Move the cache entry we're about to overwrite to the head of
261
         the list.  If either last_cache_entry or prev_cache_entry are
262
         NULL, that cache entry is already at the head.  */
263
      if (last_cache_entry != NULL && prev_cache_entry != NULL)
264
        {
265
          prev_cache_entry->link = last_cache_entry->link;
266
          last_cache_entry->link = frame_hdr_cache_head;
267
          frame_hdr_cache_head = last_cache_entry;
268
        }
269
 
270
      frame_hdr_cache_head->load_base = load_base;
271
      frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr;
272
      frame_hdr_cache_head->p_dynamic = p_dynamic;
273
      frame_hdr_cache_head->pc_low = pc_low;
274
      frame_hdr_cache_head->pc_high = pc_high;
275
    }
276
 
277
 found:
278
 
279
  if (!p_eh_frame_hdr)
280
    return 0;
281
 
282
  /* Read .eh_frame_hdr header.  */
283
  hdr = (const struct unw_eh_frame_hdr *)
284
    __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
285
  if (hdr->version != 1)
286
    return 1;
287
 
288
#ifdef CRT_GET_RFIB_DATA
289
# ifdef __i386__
290
  data->dbase = NULL;
291
  if (p_dynamic)
292
    {
293
      /* For dynamically linked executables and shared libraries,
294
         DT_PLTGOT is the gp value for that object.  */
295
      ElfW(Dyn) *dyn = (ElfW(Dyn) *)
296
        __RELOC_POINTER (p_dynamic->p_vaddr, load_base);
297
      for (; dyn->d_tag != DT_NULL ; dyn++)
298
        if (dyn->d_tag == DT_PLTGOT)
299
          {
300
            /* On IA-32, _DYNAMIC is writable and GLIBC has relocated it.  */
301
            data->dbase = (void *) dyn->d_un.d_ptr;
302
            break;
303
          }
304
    }
305
# elif defined __FRV_FDPIC__ && defined __linux__
306
  data->dbase = load_base.got_value;
307
# else
308
#  error What is DW_EH_PE_datarel base on this platform?
309
# endif
310
#endif
311
 
312
  p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
313
                                    base_from_cb_data (hdr->eh_frame_ptr_enc,
314
                                                       data),
315
                                    (const unsigned char *) (hdr + 1),
316
                                    &eh_frame);
317
 
318
  /* We require here specific table encoding to speed things up.
319
     Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
320
     as base, not the processor specific DW_EH_PE_datarel.  */
321
  if (hdr->fde_count_enc != DW_EH_PE_omit
322
      && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
323
    {
324
      _Unwind_Ptr fde_count;
325
 
326
      p = read_encoded_value_with_base (hdr->fde_count_enc,
327
                                        base_from_cb_data (hdr->fde_count_enc,
328
                                                           data),
329
                                        p, &fde_count);
330
      /* Shouldn't happen.  */
331
      if (fde_count == 0)
332
        return 1;
333
      if ((((_Unwind_Ptr) p) & 3) == 0)
334
        {
335
          struct fde_table {
336
            signed initial_loc __attribute__ ((mode (SI)));
337
            signed fde __attribute__ ((mode (SI)));
338
          };
339
          const struct fde_table *table = (const struct fde_table *) p;
340
          size_t lo, hi, mid;
341
          _Unwind_Ptr data_base = (_Unwind_Ptr) hdr;
342
          fde *f;
343
          unsigned int f_enc, f_enc_size;
344
          _Unwind_Ptr range;
345
 
346
          mid = fde_count - 1;
347
          if (data->pc < table[0].initial_loc + data_base)
348
            return 1;
349
          else if (data->pc < table[mid].initial_loc + data_base)
350
            {
351
              lo = 0;
352
              hi = mid;
353
 
354
              while (lo < hi)
355
                {
356
                  mid = (lo + hi) / 2;
357
                  if (data->pc < table[mid].initial_loc + data_base)
358
                    hi = mid;
359
                  else if (data->pc >= table[mid + 1].initial_loc + data_base)
360
                    lo = mid + 1;
361
                  else
362
                    break;
363
                }
364
 
365
              gcc_assert (lo < hi);
366
            }
367
 
368
          f = (fde *) (table[mid].fde + data_base);
369
          f_enc = get_fde_encoding (f);
370
          f_enc_size = size_of_encoded_value (f_enc);
371
          read_encoded_value_with_base (f_enc & 0x0f, 0,
372
                                        &f->pc_begin[f_enc_size], &range);
373
          if (data->pc < table[mid].initial_loc + data_base + range)
374
            data->ret = f;
375
          data->func = (void *) (table[mid].initial_loc + data_base);
376
          return 1;
377
        }
378
    }
379
 
380
  /* We have no sorted search table, so need to go the slow way.
381
     As soon as GLIBC will provide API so to notify that a library has been
382
     removed, we could cache this (and thus use search_object).  */
383
  ob.pc_begin = NULL;
384
  ob.tbase = data->tbase;
385
  ob.dbase = data->dbase;
386
  ob.u.single = (fde *) eh_frame;
387
  ob.s.i = 0;
388
  ob.s.b.mixed_encoding = 1;  /* Need to assume worst case.  */
389
  data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc);
390
  if (data->ret != NULL)
391
    {
392
      _Unwind_Ptr func;
393
      unsigned int encoding = get_fde_encoding (data->ret);
394
 
395
      read_encoded_value_with_base (encoding,
396
                                    base_from_cb_data (encoding, data),
397
                                    data->ret->pc_begin, &func);
398
      data->func = (void *) func;
399
    }
400
  return 1;
401
}
402
 
403
const fde *
404
_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
405
{
406
  struct unw_eh_callback_data data;
407
  const fde *ret;
408
 
409
  ret = _Unwind_Find_registered_FDE (pc, bases);
410
  if (ret != NULL)
411
    return ret;
412
 
413
  data.pc = (_Unwind_Ptr) pc;
414
  data.tbase = NULL;
415
  data.dbase = NULL;
416
  data.func = NULL;
417
  data.ret = NULL;
418
  data.check_cache = 1;
419
 
420
  if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
421
    return NULL;
422
 
423
  if (data.ret)
424
    {
425
      bases->tbase = data.tbase;
426
      bases->dbase = data.dbase;
427
      bases->func = data.func;
428
    }
429
  return data.ret;
430
}
431
 
432
#else
433
/* Prevent multiple include of header files.  */
434
#define _Unwind_Find_FDE _Unwind_Find_FDE
435
#include "unwind-dw2-fde.c"
436
#endif
437
 
438
#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
439
alias (_Unwind_Find_FDE);
440
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.