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