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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [unwind-dw2-fde-dip.c] - Blame information for rev 758

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

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

powered by: WebSVN 2.1.0

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