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