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