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