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