Home | History | Annotate | Download | only in dwarf
      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 (at) 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
     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
     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 *
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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