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