• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
3 	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4 
5 This file is part of libunwind.
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25 
26 /* Locate an FDE via the ELF data-structures defined by LSB v1.3
27    (http://www.linuxbase.org/spec/).  */
28 
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <limits.h>
32 
33 #include "dwarf_i.h"
34 #include "dwarf-eh.h"
35 #include "libunwind_i.h"
36 
37 struct table_entry
38   {
39     int32_t start_ip_offset;
40     int32_t fde_offset;
41   };
42 
43 #ifndef UNW_REMOTE_ONLY
44 
45 #ifdef __linux
46 #include "os-linux.h"
47 #endif
48 
49 static int
linear_search(unw_addr_space_t as,unw_word_t ip,unw_word_t eh_frame_start,unw_word_t eh_frame_end,unw_word_t fde_count,unw_proc_info_t * pi,int need_unwind_info,void * arg)50 linear_search (unw_addr_space_t as, unw_word_t ip,
51 	       unw_word_t eh_frame_start, unw_word_t eh_frame_end,
52 	       unw_word_t fde_count,
53 	       unw_proc_info_t *pi, int need_unwind_info, void *arg)
54 {
55   unw_accessors_t *a = unw_get_accessors (unw_local_addr_space);
56   unw_word_t i = 0, fde_addr, addr = eh_frame_start;
57   int ret;
58 
59   while (i++ < fde_count && addr < eh_frame_end)
60     {
61       fde_addr = addr;
62       if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, 0, arg))
63 	  < 0)
64 	return ret;
65 
66       if (ip >= pi->start_ip && ip < pi->end_ip)
67 	{
68 	  if (!need_unwind_info)
69 	    return 1;
70 	  addr = fde_addr;
71 	  if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
72 						       need_unwind_info, 0,
73 						       arg))
74 	      < 0)
75 	    return ret;
76 	  return 1;
77 	}
78     }
79   return -UNW_ENOINFO;
80 }
81 #endif /* !UNW_REMOTE_ONLY */
82 
83 #ifdef CONFIG_DEBUG_FRAME
84 /* Load .debug_frame section from FILE.  Allocates and returns space
85    in *BUF, and sets *BUFSIZE to its size.  IS_LOCAL is 1 if using the
86    local process, in which case we can search the system debug file
87    directory; 0 for other address spaces, in which case we do not; or
88    -1 for recursive calls following .gnu_debuglink.  Returns 0 on
89    success, 1 on error.  Succeeds even if the file contains no
90    .debug_frame.  */
91 /* XXX: Could use mmap; but elf_map_image keeps tons mapped in.  */
92 
93 static int
load_debug_frame(const char * file,char ** buf,size_t * bufsize,int is_local)94 load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
95 {
96   FILE *f;
97   Elf_W (Ehdr) ehdr;
98   Elf_W (Half) shstrndx;
99   Elf_W (Shdr) *sec_hdrs = NULL;
100   char *stringtab = NULL;
101   unsigned int i;
102   size_t linksize = 0;
103   char *linkbuf = NULL;
104 
105   *buf = NULL;
106   *bufsize = 0;
107 
108   f = fopen (file, "r");
109 
110   if (!f)
111     return 1;
112 
113   if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
114     goto file_error;
115 
116   shstrndx = ehdr.e_shstrndx;
117 
118   Debug (4, "opened file '%s'. Section header at offset %d\n",
119          file, (int) ehdr.e_shoff);
120 
121   fseek (f, ehdr.e_shoff, SEEK_SET);
122   sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
123   if (fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum)
124     goto file_error;
125 
126   Debug (4, "loading string table of size %zd\n",
127 	   sec_hdrs[shstrndx].sh_size);
128   stringtab = malloc (sec_hdrs[shstrndx].sh_size);
129   fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
130   if (fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f) != sec_hdrs[shstrndx].sh_size)
131     goto file_error;
132 
133   for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
134     {
135       char *secname = &stringtab[sec_hdrs[i].sh_name];
136 
137       if (strcmp (secname, ".debug_frame") == 0)
138         {
139 	  *bufsize = sec_hdrs[i].sh_size;
140 	  *buf = malloc (*bufsize);
141 
142 	  fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
143 	  if (fread (*buf, 1, *bufsize, f) != *bufsize)
144 	    goto file_error;
145 
146 	  Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
147 		 *bufsize, sec_hdrs[i].sh_offset);
148 	}
149       else if (strcmp (secname, ".gnu_debuglink") == 0)
150 	{
151 	  linksize = sec_hdrs[i].sh_size;
152 	  linkbuf = malloc (linksize);
153 
154 	  fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
155 	  if (fread (linkbuf, 1, linksize, f) != linksize)
156 	    goto file_error;
157 
158 	  Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n",
159 		 linksize, sec_hdrs[i].sh_offset);
160 	}
161     }
162 
163   free (stringtab);
164   free (sec_hdrs);
165 
166   fclose (f);
167 
168   /* Ignore separate debug files which contain a .gnu_debuglink section. */
169   if (linkbuf && is_local == -1)
170     {
171       free (linkbuf);
172       return 1;
173     }
174 
175   if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
176     {
177       char *newname, *basedir, *p;
178       static const char *debugdir = "/usr/lib/debug";
179       int ret;
180 
181       /* XXX: Don't bother with the checksum; just search for the file.  */
182       basedir = malloc (strlen (file) + 1);
183       newname = malloc (strlen (linkbuf) + strlen (debugdir)
184 			+ strlen (file) + 9);
185 
186       p = strrchr (file, '/');
187       if (p != NULL)
188 	{
189 	  memcpy (basedir, file, p - file);
190 	  basedir[p - file] = '\0';
191 	}
192       else
193 	basedir[0] = 0;
194 
195       strcpy (newname, basedir);
196       strcat (newname, "/");
197       strcat (newname, linkbuf);
198       ret = load_debug_frame (newname, buf, bufsize, -1);
199 
200       if (ret == 1)
201 	{
202 	  strcpy (newname, basedir);
203 	  strcat (newname, "/.debug/");
204 	  strcat (newname, linkbuf);
205 	  ret = load_debug_frame (newname, buf, bufsize, -1);
206 	}
207 
208       if (ret == 1 && is_local == 1)
209 	{
210 	  strcpy (newname, debugdir);
211 	  strcat (newname, basedir);
212 	  strcat (newname, "/");
213 	  strcat (newname, linkbuf);
214 	  ret = load_debug_frame (newname, buf, bufsize, -1);
215 	}
216 
217       free (basedir);
218       free (newname);
219     }
220   free (linkbuf);
221 
222   return 0;
223 
224 /* An error reading image file. Release resources and return error code */
225 file_error:
226   free(stringtab);
227   free(sec_hdrs);
228   free(linkbuf);
229   free(*buf);
230   fclose(f);
231 
232   return 1;
233 }
234 
235 /* Locate the binary which originated the contents of address ADDR. Return
236    the name of the binary in *name (space is allocated by the caller)
237    Returns 0 if a binary is successfully found, or 1 if an error occurs.  */
238 
239 /* ANDROID support update. */
240 /* Removed the find_binary_for_address function. */
241 /* End of ANDROID update. */
242 
243 /* Locate and/or try to load a debug_frame section for address ADDR.  Return
244    pointer to debug frame descriptor, or zero if not found.  */
245 
246 static struct unw_debug_frame_list *
locate_debug_info(unw_addr_space_t as,unw_word_t addr,const char * dlname,unw_word_t start,unw_word_t end)247 locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
248 		   unw_word_t start, unw_word_t end)
249 {
250   struct unw_debug_frame_list *w, *fdesc = 0;
251   int err;
252   char *buf;
253   size_t bufsize;
254   /* ANDROID support update. */
255   char *name = NULL;
256   /* End of ANDROID update. */
257 
258   /* First, see if we loaded this frame already.  */
259 
260   for (w = as->debug_frames; w; w = w->next)
261     {
262       Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end);
263       if (addr >= w->start && addr < w->end)
264 	return w;
265     }
266 
267   /* ANDROID support update. */
268   /* If the object name we receive is blank, there's still a chance of locating
269      the file by looking at the maps cache. */
270 
271   if (strcmp (dlname, "") == 0)
272     {
273 #ifdef UNW_LOCAL_ONLY
274       name = map_local_get_image_name (addr);
275 #else
276       struct map_info *map = map_find_from_addr (as->map_list, addr);
277       if (map)
278         name = strdup (map->path);
279 #endif
280       if (!name)
281   /* End of ANDROID update. */
282         {
283 	  Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n",
284 		 (uint64_t) addr);
285           return 0;
286 	}
287     }
288   else
289     name = (char*) dlname;
290 
291   err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
292 
293   if (!err)
294     {
295       fdesc = malloc (sizeof (struct unw_debug_frame_list));
296 
297       fdesc->start = start;
298       fdesc->end = end;
299       fdesc->debug_frame = buf;
300       fdesc->debug_frame_size = bufsize;
301       fdesc->index = NULL;
302       fdesc->next = as->debug_frames;
303 
304       as->debug_frames = fdesc;
305     }
306 
307   /* ANDROID support update. */
308   if (name != dlname)
309     free(name);
310   /* End of ANDROID update. */
311 
312   return fdesc;
313 }
314 
315 struct debug_frame_tab
316   {
317     struct table_entry *tab;
318     uint32_t length;
319     uint32_t size;
320   };
321 
322 static void
debug_frame_tab_append(struct debug_frame_tab * tab,unw_word_t fde_offset,unw_word_t start_ip)323 debug_frame_tab_append (struct debug_frame_tab *tab,
324 			unw_word_t fde_offset, unw_word_t start_ip)
325 {
326   unsigned int length = tab->length;
327 
328   if (length == tab->size)
329     {
330       tab->size *= 2;
331       tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
332     }
333 
334   tab->tab[length].fde_offset = fde_offset;
335   tab->tab[length].start_ip_offset = start_ip;
336 
337   tab->length = length + 1;
338 }
339 
340 static void
debug_frame_tab_shrink(struct debug_frame_tab * tab)341 debug_frame_tab_shrink (struct debug_frame_tab *tab)
342 {
343   if (tab->size > tab->length)
344     {
345       tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length);
346       tab->size = tab->length;
347     }
348 }
349 
350 static int
debug_frame_tab_compare(const void * a,const void * b)351 debug_frame_tab_compare (const void *a, const void *b)
352 {
353   const struct table_entry *fa = a, *fb = b;
354 
355   if (fa->start_ip_offset > fb->start_ip_offset)
356     return 1;
357   else if (fa->start_ip_offset < fb->start_ip_offset)
358     return -1;
359   else
360     return 0;
361 }
362 
363 PROTECTED int
dwarf_find_debug_frame(int found,unw_dyn_info_t * di_debug,unw_word_t ip,unw_word_t segbase,const char * obj_name,unw_word_t start,unw_word_t end)364 dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
365 			unw_word_t segbase, const char* obj_name,
366 			unw_word_t start, unw_word_t end)
367 {
368   unw_dyn_info_t *di;
369   struct unw_debug_frame_list *fdesc = 0;
370   unw_accessors_t *a;
371   unw_word_t addr;
372 
373   Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
374   di = di_debug;
375 
376   fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
377 
378   if (!fdesc)
379     {
380       Debug (15, "couldn't load .debug_frame\n");
381       return found;
382     }
383   else
384     {
385       char *buf;
386       size_t bufsize;
387       unw_word_t item_start, item_end = 0;
388       uint32_t u32val = 0;
389       uint64_t cie_id = 0;
390       struct debug_frame_tab tab;
391 
392       Debug (15, "loaded .debug_frame\n");
393 
394       buf = fdesc->debug_frame;
395       bufsize = fdesc->debug_frame_size;
396 
397       if (bufsize == 0)
398        {
399          Debug (15, "zero-length .debug_frame\n");
400          return found;
401        }
402 
403       /* Now create a binary-search table, if it does not already exist.  */
404       if (!fdesc->index)
405        {
406          addr = (unw_word_t) (uintptr_t) buf;
407 
408          a = unw_get_accessors (unw_local_addr_space);
409 
410          /* Find all FDE entries in debug_frame, and make into a sorted
411             index.  */
412 
413          tab.length = 0;
414          tab.size = 16;
415          tab.tab = calloc (tab.size, sizeof (struct table_entry));
416 
417          while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
418            {
419              uint64_t id_for_cie;
420              item_start = addr;
421 
422              dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
423 
424              if (u32val == 0)
425                break;
426              else if (u32val != 0xffffffff)
427                {
428                  uint32_t cie_id32 = 0;
429                  item_end = addr + u32val;
430                  dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
431                                 NULL);
432                  cie_id = cie_id32;
433                  id_for_cie = 0xffffffff;
434                }
435              else
436                {
437                  uint64_t u64val = 0;
438                  /* Extended length.  */
439                  dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
440                  item_end = addr + u64val;
441 
442                  dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
443                  id_for_cie = 0xffffffffffffffffull;
444                }
445 
446              /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
447 
448              if (cie_id == id_for_cie)
449                ;
450              /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
451              else
452                {
453                  unw_word_t fde_addr = item_start;
454                  unw_proc_info_t this_pi;
455                  int err;
456 
457                  /*Debug (1, "Found FDE at %.8x\n", item_start);*/
458 
459                  err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
460                                                          a, &fde_addr,
461                                                          &this_pi, 0,
462                                                          (uintptr_t) buf,
463                                                          NULL);
464                  if (err == 0)
465                    {
466                      Debug (15, "start_ip = %lx, end_ip = %lx\n",
467                             (long) this_pi.start_ip, (long) this_pi.end_ip);
468                      debug_frame_tab_append (&tab,
469                                              item_start - (unw_word_t) (uintptr_t) buf,
470                                              this_pi.start_ip);
471                    }
472                  /*else
473                    Debug (1, "FDE parse failed\n");*/
474                }
475 
476              addr = item_end;
477            }
478 
479          debug_frame_tab_shrink (&tab);
480          qsort (tab.tab, tab.length, sizeof (struct table_entry),
481                 debug_frame_tab_compare);
482          /* for (i = 0; i < tab.length; i++)
483             {
484             fprintf (stderr, "ip %x, fde offset %x\n",
485             (int) tab.tab[i].start_ip_offset,
486             (int) tab.tab[i].fde_offset);
487             }*/
488          fdesc->index = tab.tab;
489          fdesc->index_size = tab.length;
490        }
491 
492       di->format = UNW_INFO_FORMAT_TABLE;
493       di->start_ip = fdesc->start;
494       di->end_ip = fdesc->end;
495       di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
496       di->u.ti.table_data = (unw_word_t *) fdesc;
497       di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
498       di->u.ti.segbase = segbase;
499 
500       found = 1;
501       Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
502             "gp=0x%lx, table_data=0x%lx\n",
503             (char *) (uintptr_t) di->u.ti.name_ptr,
504             (long) di->u.ti.segbase, (long) di->u.ti.table_len,
505             (long) di->gp, (long) di->u.ti.table_data);
506     }
507   return found;
508 }
509 
510 #endif /* CONFIG_DEBUG_FRAME */
511 
512 #ifndef UNW_REMOTE_ONLY
513 
514 /* ptr is a pointer to a dwarf_callback_data structure and, on entry,
515    member ip contains the instruction-pointer we're looking
516    for.  */
517 HIDDEN int
dwarf_callback(struct dl_phdr_info * info,size_t size,void * ptr)518 dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
519 {
520   struct dwarf_callback_data *cb_data = ptr;
521   unw_dyn_info_t *di = &cb_data->di;
522   const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
523   unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
524   Elf_W(Addr) load_base, max_load_addr = 0;
525   int ret, need_unwind_info = cb_data->need_unwind_info;
526   unw_proc_info_t *pi = cb_data->pi;
527   struct dwarf_eh_frame_hdr *hdr;
528   unw_accessors_t *a;
529   long n;
530   int found = 0;
531 #ifdef CONFIG_DEBUG_FRAME
532   unw_word_t start, end;
533 #endif /* CONFIG_DEBUG_FRAME*/
534 
535   ip = cb_data->ip;
536 
537   /* Make sure struct dl_phdr_info is at least as big as we need.  */
538   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
539 	     + sizeof (info->dlpi_phnum))
540     return -1;
541 
542   Debug (15, "checking %s, base=0x%lx)\n",
543 	 info->dlpi_name, (long) info->dlpi_addr);
544 
545   phdr = info->dlpi_phdr;
546   load_base = info->dlpi_addr;
547   p_text = NULL;
548   p_eh_hdr = NULL;
549   p_dynamic = NULL;
550 
551   /* See if PC falls into one of the loaded segments.  Find the
552      eh-header segment at the same time.  */
553   for (n = info->dlpi_phnum; --n >= 0; phdr++)
554     {
555       if (phdr->p_type == PT_LOAD)
556 	{
557 	  Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
558 
559 	  if (ip >= vaddr && ip < vaddr + phdr->p_memsz)
560 	    p_text = phdr;
561 
562 	  if (vaddr + phdr->p_filesz > max_load_addr)
563 	    max_load_addr = vaddr + phdr->p_filesz;
564 	}
565       else if (phdr->p_type == PT_GNU_EH_FRAME)
566 	p_eh_hdr = phdr;
567       else if (phdr->p_type == PT_DYNAMIC)
568 	p_dynamic = phdr;
569     }
570 
571   if (!p_text)
572     return 0;
573 
574   if (p_eh_hdr)
575     {
576       if (p_dynamic)
577 	{
578 	  /* For dynamicly linked executables and shared libraries,
579 	     DT_PLTGOT is the value that data-relative addresses are
580 	     relative to for that object.  We call this the "gp".  */
581 	  Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
582 	  for (; dyn->d_tag != DT_NULL; ++dyn)
583 	    if (dyn->d_tag == DT_PLTGOT)
584 	      {
585 		/* Assume that _DYNAMIC is writable and GLIBC has
586 		   relocated it (true for x86 at least).  */
587 		di->gp = dyn->d_un.d_ptr;
588 		break;
589 	      }
590 	}
591       else
592 	/* Otherwise this is a static executable with no _DYNAMIC.  Assume
593 	   that data-relative addresses are relative to 0, i.e.,
594 	   absolute.  */
595 	di->gp = 0;
596       pi->gp = di->gp;
597 
598       hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
599       if (hdr->version != DW_EH_VERSION)
600 	{
601 	  Debug (1, "table `%s' has unexpected version %d\n",
602 		 info->dlpi_name, hdr->version);
603 	  return 0;
604 	}
605 
606       a = unw_get_accessors (unw_local_addr_space);
607       addr = (unw_word_t) (uintptr_t) (hdr + 1);
608 
609       /* (Optionally) read eh_frame_ptr: */
610       if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
611 					     &addr, hdr->eh_frame_ptr_enc, pi,
612 					     &eh_frame_start, NULL)) < 0)
613 	return ret;
614 
615       /* (Optionally) read fde_count: */
616       if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
617 					     &addr, hdr->fde_count_enc, pi,
618 					     &fde_count, NULL)) < 0)
619 	return ret;
620 
621       if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
622 	{
623 	  /* If there is no search table or it has an unsupported
624 	     encoding, fall back on linear search.  */
625 	  if (hdr->table_enc == DW_EH_PE_omit)
626             /* ANDROID support update. */
627 	    {
628             /* End of ANDROID update. */
629 	      Debug (4, "table `%s' lacks search table; doing linear search\n",
630 		     info->dlpi_name);
631             /* ANDROID support update. */
632 	    }
633             /* End of ANDROID update. */
634 	  else
635             /* ANDROID support update. */
636 	    {
637             /* End of ANDROID update. */
638 	      Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
639 		     info->dlpi_name, hdr->table_enc);
640             /* ANDROID support update. */
641 	    }
642             /* End of ANDROID update. */
643 
644 	  eh_frame_end = max_load_addr;	/* XXX can we do better? */
645 
646 	  if (hdr->fde_count_enc == DW_EH_PE_omit)
647 	    fde_count = ~0UL;
648 	  if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
649 	    abort ();
650 
651 	  /* XXX we know how to build a local binary search table for
652 	     .debug_frame, so we could do that here too.  */
653 	  cb_data->single_fde = 1;
654 	  found = linear_search (unw_local_addr_space, ip,
655 				 eh_frame_start, eh_frame_end, fde_count,
656 				 pi, need_unwind_info, NULL);
657 	  if (found != 1)
658 	    found = 0;
659 	}
660       else
661 	{
662 	  di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
663 	  di->start_ip = p_text->p_vaddr + load_base;
664 	  di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
665 	  di->u.rti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
666 	  di->u.rti.table_data = addr;
667 	  assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0);
668 	  di->u.rti.table_len = (fde_count * sizeof (struct table_entry)
669 				 / sizeof (unw_word_t));
670 	  /* For the binary-search table in the eh_frame_hdr, data-relative
671 	     means relative to the start of that section... */
672 	  di->u.rti.segbase = (unw_word_t) (uintptr_t) hdr;
673 
674 	  found = 1;
675 	  Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
676 		 "table_data=0x%lx\n", (char *) (uintptr_t) di->u.rti.name_ptr,
677 		 (long) di->u.rti.segbase, (long) di->u.rti.table_len,
678 		 (long) di->gp, (long) di->u.rti.table_data);
679 	}
680     }
681 
682 #ifdef CONFIG_DEBUG_FRAME
683   /* Find the start/end of the described region by parsing the phdr_info
684      structure.  */
685   start = (unw_word_t) -1;
686   end = 0;
687 
688   for (n = 0; n < info->dlpi_phnum; n++)
689     {
690       if (info->dlpi_phdr[n].p_type == PT_LOAD)
691         {
692 	  unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr;
693           unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz;
694 
695 	  if (seg_start < start)
696 	    start = seg_start;
697 
698 	  if (seg_end > end)
699 	    end = seg_end;
700 	}
701     }
702 
703   found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip,
704 				  info->dlpi_addr, info->dlpi_name, start,
705 				  end);
706 #endif  /* CONFIG_DEBUG_FRAME */
707 
708   return found;
709 }
710 
711 HIDDEN int
dwarf_find_proc_info(unw_addr_space_t as,unw_word_t ip,unw_proc_info_t * pi,int need_unwind_info,void * arg)712 dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
713 		      unw_proc_info_t *pi, int need_unwind_info, void *arg)
714 {
715   struct dwarf_callback_data cb_data;
716   intrmask_t saved_mask;
717   int ret;
718 
719   Debug (14, "looking for IP=0x%lx\n", (long) ip);
720 
721   memset (&cb_data, 0, sizeof (cb_data));
722   cb_data.ip = ip;
723   cb_data.pi = pi;
724   cb_data.need_unwind_info = need_unwind_info;
725   cb_data.di.format = -1;
726   cb_data.di_debug.format = -1;
727 
728   SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
729   ret = dl_iterate_phdr (dwarf_callback, &cb_data);
730   SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
731 
732   if (ret <= 0)
733     {
734       Debug (14, "IP=0x%lx not found\n", (long) ip);
735       return -UNW_ENOINFO;
736     }
737 
738   if (cb_data.single_fde)
739     /* already got the result in *pi */
740     return 0;
741 
742   /* search the table: */
743   if (cb_data.di.format != -1)
744     ret = dwarf_search_unwind_table (as, ip, &cb_data.di,
745 				      pi, need_unwind_info, arg);
746   else
747     ret = -UNW_ENOINFO;
748 
749   if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
750     ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi,
751 				     need_unwind_info, arg);
752   return ret;
753 }
754 
755 static inline const struct table_entry *
lookup(const struct table_entry * table,size_t table_size,int32_t rel_ip)756 lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip)
757 {
758   unsigned long table_len = table_size / sizeof (struct table_entry);
759   const struct table_entry *e = NULL;
760   unsigned long lo, hi, mid;
761 
762   /* do a binary search for right entry: */
763   for (lo = 0, hi = table_len; lo < hi;)
764     {
765       mid = (lo + hi) / 2;
766       e = table + mid;
767       Debug (15, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset);
768       if (rel_ip < e->start_ip_offset)
769 	hi = mid;
770       else
771 	lo = mid + 1;
772     }
773   if (hi <= 0)
774 	return NULL;
775   e = table + hi - 1;
776   return e;
777 }
778 
779 #endif /* !UNW_REMOTE_ONLY */
780 
781 #ifndef UNW_LOCAL_ONLY
782 
783 /* Lookup an unwind-table entry in remote memory.  Returns 1 if an
784    entry is found, 0 if no entry is found, negative if an error
785    occurred reading remote memory.  */
786 static int
remote_lookup(unw_addr_space_t as,unw_word_t table,size_t table_size,int32_t rel_ip,struct table_entry * e,void * arg)787 remote_lookup (unw_addr_space_t as,
788 	       unw_word_t table, size_t table_size, int32_t rel_ip,
789 	       struct table_entry *e, void *arg)
790 {
791   unsigned long table_len = table_size / sizeof (struct table_entry);
792   unw_accessors_t *a = unw_get_accessors (as);
793   unsigned long lo, hi, mid;
794   unw_word_t e_addr = 0;
795   int32_t start;
796   int ret;
797 
798   /* do a binary search for right entry: */
799   for (lo = 0, hi = table_len; lo < hi;)
800     {
801       mid = (lo + hi) / 2;
802       e_addr = table + mid * sizeof (struct table_entry);
803       if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0)
804 	return ret;
805 
806       if (rel_ip < start)
807 	hi = mid;
808       else
809 	lo = mid + 1;
810     }
811   if (hi <= 0)
812     return 0;
813   e_addr = table + (hi - 1) * sizeof (struct table_entry);
814   if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0
815    || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0)
816     return ret;
817   return 1;
818 }
819 
820 #endif /* !UNW_LOCAL_ONLY */
821 
822 PROTECTED int
dwarf_search_unwind_table(unw_addr_space_t as,unw_word_t ip,unw_dyn_info_t * di,unw_proc_info_t * pi,int need_unwind_info,void * arg)823 dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
824 			   unw_dyn_info_t *di, unw_proc_info_t *pi,
825 			   int need_unwind_info, void *arg)
826 {
827   const struct table_entry *e = NULL, *table;
828   unw_word_t segbase = 0, fde_addr;
829   unw_accessors_t *a;
830 #ifndef UNW_LOCAL_ONLY
831   struct table_entry ent;
832 #endif
833   int ret;
834   unw_word_t debug_frame_base;
835   size_t table_len;
836 
837 #ifdef UNW_REMOTE_ONLY
838   assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE);
839 #else
840   assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
841 	  || di->format == UNW_INFO_FORMAT_TABLE);
842 #endif
843   assert (ip >= di->start_ip && ip < di->end_ip);
844 
845   if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
846     {
847       table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
848       table_len = di->u.rti.table_len * sizeof (unw_word_t);
849       debug_frame_base = 0;
850     }
851   else
852     {
853 #ifndef UNW_REMOTE_ONLY
854       struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
855 
856       /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
857          space.  Both the index and the unwind tables live in local memory, but
858          the address space to check for properties like the address size and
859          endianness is the target one.  */
860       as = unw_local_addr_space;
861       table = fdesc->index;
862       table_len = fdesc->index_size * sizeof (struct table_entry);
863       debug_frame_base = (uintptr_t) fdesc->debug_frame;
864 #endif
865     }
866 
867   a = unw_get_accessors (as);
868 
869 #ifndef UNW_REMOTE_ONLY
870   if (as == unw_local_addr_space)
871     {
872       segbase = di->u.rti.segbase;
873       e = lookup (table, table_len, ip - segbase);
874     }
875   else
876 #endif
877     {
878 #ifndef UNW_LOCAL_ONLY
879       segbase = di->u.rti.segbase;
880       if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
881 				ip - segbase, &ent, arg)) < 0)
882 	return ret;
883       if (ret)
884 	e = &ent;
885       else
886 	e = NULL;	/* no info found */
887 #endif
888     }
889   if (!e)
890     {
891       Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n",
892 	     (long) ip, (long) di->start_ip, (long) di->end_ip);
893       /* IP is inside this table's range, but there is no explicit
894 	 unwind info.  */
895       return -UNW_ENOINFO;
896     }
897   Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
898 	 (long) ip, (long) (e->start_ip_offset));
899   if (debug_frame_base)
900     fde_addr = e->fde_offset + debug_frame_base;
901   else
902     fde_addr = e->fde_offset + segbase;
903   Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, "
904 	    "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
905 	    (long) debug_frame_base, (long) fde_addr);
906   if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
907 					       need_unwind_info,
908 					       debug_frame_base, arg)) < 0)
909     return ret;
910 
911   /* .debug_frame uses an absolute encoding that does not know about any
912      shared library relocation.  */
913   if (di->format == UNW_INFO_FORMAT_TABLE)
914     {
915       pi->start_ip += segbase;
916       pi->end_ip += segbase;
917       pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
918     }
919 
920   if (ip < pi->start_ip || ip >= pi->end_ip)
921     {
922       /* ANDROID support update. */
923       if (need_unwind_info && pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE)
924         {
925           /* Free the memory used if the call fails. Otherwise, when there
926            * is a mix of dwarf and other unwind data, the memory allocated
927            * will be leaked.
928            */
929           mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
930           pi->unwind_info = NULL;
931         }
932       /* End of ANDROID support update. */
933       return -UNW_ENOINFO;
934     }
935 
936   return 0;
937 }
938 
939 HIDDEN void
dwarf_put_unwind_info(unw_addr_space_t as,unw_proc_info_t * pi,void * arg)940 dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
941 {
942   return;	/* always a nop */
943 }
944