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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [unwind-dw2-fde-glibc.c] - Blame information for rev 309

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

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

powered by: WebSVN 2.1.0

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