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