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