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