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