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