1 /* Copyright (C) 2001-2014 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
base_from_cb_data(unsigned char encoding,struct unw_eh_callback_data * data)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
_Unwind_IteratePhdrCallback(struct dl_phdr_info * info,size_t size,void * ptr)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 *
_Unwind_Find_FDE(void * pc,struct dwarf_eh_bases * bases)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
482