Gfind_proc_info-lsb.c revision b5ae16cf71b577df7462e499b6c6ce2729fc50a3
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, 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 %ld\n",
127	   (long) 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 %ld\n",
147		 *bufsize, (long) 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 %ld\n",
159		 linksize, (long) 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 */
225file_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
246static struct unw_debug_frame_list *
247locate_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
315struct debug_frame_tab
316  {
317    struct table_entry *tab;
318    uint32_t length;
319    uint32_t size;
320  };
321
322static void
323debug_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
340static void
341debug_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
350static int
351debug_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
363PROTECTED int
364dwarf_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.  */
517HIDDEN int
518dwarf_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
711HIDDEN int
712dwarf_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
755static inline const struct table_entry *
756lookup (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.  */
786static int
787remote_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
822PROTECTED int
823dwarf_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
939HIDDEN void
940dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
941{
942  return;	/* always a nop */
943}
944