1d77787f2SJonathan Schleifer/* libunwind - a platform-independent unwind library
2d77787f2SJonathan Schleifer   Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
3d77787f2SJonathan Schleifer        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4d77787f2SJonathan Schleifer
5d77787f2SJonathan SchleiferThis file is part of libunwind.
6d77787f2SJonathan Schleifer
7d77787f2SJonathan SchleiferPermission is hereby granted, free of charge, to any person obtaining
8d77787f2SJonathan Schleifera copy of this software and associated documentation files (the
9d77787f2SJonathan Schleifer"Software"), to deal in the Software without restriction, including
10d77787f2SJonathan Schleiferwithout limitation the rights to use, copy, modify, merge, publish,
11d77787f2SJonathan Schleiferdistribute, sublicense, and/or sell copies of the Software, and to
12d77787f2SJonathan Schleiferpermit persons to whom the Software is furnished to do so, subject to
13d77787f2SJonathan Schleiferthe following conditions:
14d77787f2SJonathan Schleifer
15d77787f2SJonathan SchleiferThe above copyright notice and this permission notice shall be
16d77787f2SJonathan Schleiferincluded in all copies or substantial portions of the Software.
17d77787f2SJonathan Schleifer
18d77787f2SJonathan SchleiferTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19d77787f2SJonathan SchleiferEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20d77787f2SJonathan SchleiferMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21d77787f2SJonathan SchleiferNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22d77787f2SJonathan SchleiferLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23d77787f2SJonathan SchleiferOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24d77787f2SJonathan SchleiferWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25d77787f2SJonathan Schleifer
26d77787f2SJonathan Schleifer/* Locate an FDE via the ELF data-structures defined by LSB v1.3
27d77787f2SJonathan Schleifer   (http://www.linuxbase.org/spec/).  */
28d77787f2SJonathan Schleifer
29d77787f2SJonathan Schleifer#include <stddef.h>
30d77787f2SJonathan Schleifer#include <stdio.h>
31d77787f2SJonathan Schleifer#include <limits.h>
32d77787f2SJonathan Schleifer
33d77787f2SJonathan Schleifer#include "dwarf_i.h"
34d77787f2SJonathan Schleifer#include "dwarf-eh.h"
35d77787f2SJonathan Schleifer#include "libunwind_i.h"
36d77787f2SJonathan Schleifer
37d77787f2SJonathan Schleiferstruct table_entry
38d77787f2SJonathan Schleifer  {
39d77787f2SJonathan Schleifer    int32_t start_ip_offset;
40d77787f2SJonathan Schleifer    int32_t fde_offset;
41d77787f2SJonathan Schleifer  };
42d77787f2SJonathan Schleifer
43d77787f2SJonathan Schleifer
44d77787f2SJonathan Schleiferstatic inline const struct table_entry *
45d77787f2SJonathan Schleiferlookup (const struct table_entry *table, size_t table_size, int32_t rel_ip);
46d77787f2SJonathan Schleifer
47d77787f2SJonathan Schleiferstatic int
48d77787f2SJonathan Schleiferremote_lookup (unw_addr_space_t as,
49d77787f2SJonathan Schleifer	       unw_word_t table, size_t table_size, int32_t rel_ip,
50d77787f2SJonathan Schleifer	       struct table_entry *e, void *arg);
51d77787f2SJonathan Schleifer
52d77787f2SJonathan Schleifer
53d77787f2SJonathan Schleifer#ifndef UNW_REMOTE_ONLY
54d77787f2SJonathan Schleifer
55d77787f2SJonathan Schleifer#ifdef __linux
56d77787f2SJonathan Schleifer#include "os-linux.h"
57d77787f2SJonathan Schleifer#endif
58d77787f2SJonathan Schleifer
59d77787f2SJonathan Schleiferstatic int
60d77787f2SJonathan Schleiferlinear_search (unw_addr_space_t as, unw_word_t ip,
61d77787f2SJonathan Schleifer               unw_word_t eh_frame_start, unw_word_t eh_frame_end,
62d77787f2SJonathan Schleifer               unw_word_t fde_count,
63d77787f2SJonathan Schleifer               unw_word_t *fde_addr, int need_unwind_info, void *arg)
64d77787f2SJonathan Schleifer{
65d77787f2SJonathan Schleifer  unw_accessors_t *a = unw_get_accessors (unw_local_addr_space);
66d77787f2SJonathan Schleifer  unw_word_t i = 0, faddr, addr = eh_frame_start;
67d77787f2SJonathan Schleifer  unw_proc_info_t pi;
68d77787f2SJonathan Schleifer  int ret;
69d77787f2SJonathan Schleifer
70d77787f2SJonathan Schleifer  while (i++ < fde_count && addr < eh_frame_end)
71d77787f2SJonathan Schleifer    {
72d77787f2SJonathan Schleifer      *fde_addr = addr;
73d77787f2SJonathan Schleifer      if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, &pi,
74d77787f2SJonathan Schleifer                                                   eh_frame_start,
75d77787f2SJonathan Schleifer                                                   0, 0, arg)) < 0)
76d77787f2SJonathan Schleifer        return ret;
77d77787f2SJonathan Schleifer
78d77787f2SJonathan Schleifer      if (ip >= pi.start_ip && ip < pi.end_ip)
79d77787f2SJonathan Schleifer        {
80d77787f2SJonathan Schleifer          *fde_addr = faddr;
81d77787f2SJonathan Schleifer
82d77787f2SJonathan Schleifer          if (!need_unwind_info)
83d77787f2SJonathan Schleifer            return 0;
84d77787f2SJonathan Schleifer
85d77787f2SJonathan Schleifer          addr = faddr;
86d77787f2SJonathan Schleifer          if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, &pi,
87d77787f2SJonathan Schleifer                                                       eh_frame_start,
88d77787f2SJonathan Schleifer                                                       need_unwind_info, 0,
89d77787f2SJonathan Schleifer                                                       arg))
90d77787f2SJonathan Schleifer              < 0)
91d77787f2SJonathan Schleifer            return ret;
92d77787f2SJonathan Schleifer          return 0;
93d77787f2SJonathan Schleifer        }
94d77787f2SJonathan Schleifer    }
95d77787f2SJonathan Schleifer  return -UNW_ENOINFO;
96d77787f2SJonathan Schleifer}
97d77787f2SJonathan Schleifer#endif /* !UNW_REMOTE_ONLY */
98d77787f2SJonathan Schleifer
99d77787f2SJonathan Schleifer#ifdef CONFIG_DEBUG_FRAME
100d77787f2SJonathan Schleifer/* Load .debug_frame section from FILE.  Allocates and returns space
101d77787f2SJonathan Schleifer   in *BUF, and sets *BUFSIZE to its size.  IS_LOCAL is 1 if using the
102d77787f2SJonathan Schleifer   local process, in which case we can search the system debug file
103d77787f2SJonathan Schleifer   directory; 0 for other address spaces, in which case we do not; or
104d77787f2SJonathan Schleifer   -1 for recursive calls following .gnu_debuglink.  Returns 0 on
105d77787f2SJonathan Schleifer   success, 1 on error.  Succeeds even if the file contains no
106d77787f2SJonathan Schleifer   .debug_frame.  */
107d77787f2SJonathan Schleifer/* XXX: Could use mmap; but elf_map_image keeps tons mapped in.  */
108d77787f2SJonathan Schleifer
109d77787f2SJonathan Schleiferstatic int
110d77787f2SJonathan Schleiferload_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
111d77787f2SJonathan Schleifer{
112d77787f2SJonathan Schleifer  FILE *f;
113d77787f2SJonathan Schleifer  Elf_W (Ehdr) ehdr;
114d77787f2SJonathan Schleifer  Elf_W (Half) shstrndx;
115d77787f2SJonathan Schleifer  Elf_W (Shdr) *sec_hdrs = NULL;
116d77787f2SJonathan Schleifer  char *stringtab = NULL;
117d77787f2SJonathan Schleifer  unsigned int i;
118d77787f2SJonathan Schleifer  size_t linksize = 0;
119d77787f2SJonathan Schleifer  char *linkbuf = NULL;
120d77787f2SJonathan Schleifer
121d77787f2SJonathan Schleifer  *buf = NULL;
122d77787f2SJonathan Schleifer  *bufsize = 0;
123d77787f2SJonathan Schleifer
124d77787f2SJonathan Schleifer  f = fopen (file, "r");
125d77787f2SJonathan Schleifer
126d77787f2SJonathan Schleifer  if (!f)
127d77787f2SJonathan Schleifer    return 1;
128d77787f2SJonathan Schleifer
129d77787f2SJonathan Schleifer  if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
130d77787f2SJonathan Schleifer    goto file_error;
131d77787f2SJonathan Schleifer
132d77787f2SJonathan Schleifer  shstrndx = ehdr.e_shstrndx;
133d77787f2SJonathan Schleifer
134d77787f2SJonathan Schleifer  Debug (4, "opened file '%s'. Section header at offset %d\n",
135d77787f2SJonathan Schleifer         file, (int) ehdr.e_shoff);
136d77787f2SJonathan Schleifer
137d77787f2SJonathan Schleifer  fseek (f, ehdr.e_shoff, SEEK_SET);
138d77787f2SJonathan Schleifer  sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
139d77787f2SJonathan Schleifer  if (fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum)
140d77787f2SJonathan Schleifer    goto file_error;
141d77787f2SJonathan Schleifer
142d77787f2SJonathan Schleifer  Debug (4, "loading string table of size %zd\n",
143d77787f2SJonathan Schleifer           sec_hdrs[shstrndx].sh_size);
144d77787f2SJonathan Schleifer  stringtab = malloc (sec_hdrs[shstrndx].sh_size);
145d77787f2SJonathan Schleifer  fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
146d77787f2SJonathan Schleifer  if (fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f) != sec_hdrs[shstrndx].sh_size)
147d77787f2SJonathan Schleifer    goto file_error;
148d77787f2SJonathan Schleifer
149d77787f2SJonathan Schleifer  for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
150d77787f2SJonathan Schleifer    {
151d77787f2SJonathan Schleifer      char *secname = &stringtab[sec_hdrs[i].sh_name];
152d77787f2SJonathan Schleifer
153d77787f2SJonathan Schleifer      if (strcmp (secname, ".debug_frame") == 0)
154d77787f2SJonathan Schleifer        {
155d77787f2SJonathan Schleifer          *bufsize = sec_hdrs[i].sh_size;
156d77787f2SJonathan Schleifer          *buf = malloc (*bufsize);
157d77787f2SJonathan Schleifer
158d77787f2SJonathan Schleifer          fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
159d77787f2SJonathan Schleifer          if (fread (*buf, 1, *bufsize, f) != *bufsize)
160d77787f2SJonathan Schleifer            goto file_error;
161d77787f2SJonathan Schleifer
162d77787f2SJonathan Schleifer          Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
163d77787f2SJonathan Schleifer                 *bufsize, sec_hdrs[i].sh_offset);
164d77787f2SJonathan Schleifer        }
165d77787f2SJonathan Schleifer      else if (strcmp (secname, ".gnu_debuglink") == 0)
166d77787f2SJonathan Schleifer        {
167d77787f2SJonathan Schleifer          linksize = sec_hdrs[i].sh_size;
168d77787f2SJonathan Schleifer          linkbuf = malloc (linksize);
169d77787f2SJonathan Schleifer
170d77787f2SJonathan Schleifer          fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
171d77787f2SJonathan Schleifer          if (fread (linkbuf, 1, linksize, f) != linksize)
172d77787f2SJonathan Schleifer            goto file_error;
173d77787f2SJonathan Schleifer
174d77787f2SJonathan Schleifer          Debug (4, "read %zd bytes of .gnu_debuglink from offset %zd\n",
175d77787f2SJonathan Schleifer                 linksize, sec_hdrs[i].sh_offset);
176d77787f2SJonathan Schleifer        }
177d77787f2SJonathan Schleifer    }
178d77787f2SJonathan Schleifer
179d77787f2SJonathan Schleifer  free (stringtab);
180d77787f2SJonathan Schleifer  free (sec_hdrs);
181d77787f2SJonathan Schleifer
182d77787f2SJonathan Schleifer  fclose (f);
183d77787f2SJonathan Schleifer
184d77787f2SJonathan Schleifer  /* Ignore separate debug files which contain a .gnu_debuglink section. */
185d77787f2SJonathan Schleifer  if (linkbuf && is_local == -1)
186d77787f2SJonathan Schleifer    {
187d77787f2SJonathan Schleifer      free (linkbuf);
188d77787f2SJonathan Schleifer      return 1;
189d77787f2SJonathan Schleifer    }
190d77787f2SJonathan Schleifer
191d77787f2SJonathan Schleifer  if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
192d77787f2SJonathan Schleifer    {
193d77787f2SJonathan Schleifer      char *newname, *basedir, *p;
194d77787f2SJonathan Schleifer      static const char *debugdir = "/usr/lib/debug";
195d77787f2SJonathan Schleifer      int ret;
196d77787f2SJonathan Schleifer
197d77787f2SJonathan Schleifer      /* XXX: Don't bother with the checksum; just search for the file.  */
198d77787f2SJonathan Schleifer      basedir = malloc (strlen (file) + 1);
199d77787f2SJonathan Schleifer      newname = malloc (strlen (linkbuf) + strlen (debugdir)
200d77787f2SJonathan Schleifer                        + strlen (file) + 9);
201d77787f2SJonathan Schleifer
202d77787f2SJonathan Schleifer      p = strrchr (file, '/');
203d77787f2SJonathan Schleifer      if (p != NULL)
204d77787f2SJonathan Schleifer        {
205d77787f2SJonathan Schleifer          memcpy (basedir, file, p - file);
206d77787f2SJonathan Schleifer          basedir[p - file] = '\0';
207d77787f2SJonathan Schleifer        }
208d77787f2SJonathan Schleifer      else
209d77787f2SJonathan Schleifer        basedir[0] = 0;
210d77787f2SJonathan Schleifer
211d77787f2SJonathan Schleifer      strcpy (newname, basedir);
212d77787f2SJonathan Schleifer      strcat (newname, "/");
213d77787f2SJonathan Schleifer      strcat (newname, linkbuf);
214d77787f2SJonathan Schleifer      ret = load_debug_frame (newname, buf, bufsize, -1);
215d77787f2SJonathan Schleifer
216d77787f2SJonathan Schleifer      if (ret == 1)
217d77787f2SJonathan Schleifer        {
218d77787f2SJonathan Schleifer          strcpy (newname, basedir);
219d77787f2SJonathan Schleifer          strcat (newname, "/.debug/");
220d77787f2SJonathan Schleifer          strcat (newname, linkbuf);
221d77787f2SJonathan Schleifer          ret = load_debug_frame (newname, buf, bufsize, -1);
222d77787f2SJonathan Schleifer        }
223d77787f2SJonathan Schleifer
224d77787f2SJonathan Schleifer      if (ret == 1 && is_local == 1)
225d77787f2SJonathan Schleifer        {
226d77787f2SJonathan Schleifer          strcpy (newname, debugdir);
227d77787f2SJonathan Schleifer          strcat (newname, basedir);
228d77787f2SJonathan Schleifer          strcat (newname, "/");
229d77787f2SJonathan Schleifer          strcat (newname, linkbuf);
230d77787f2SJonathan Schleifer          ret = load_debug_frame (newname, buf, bufsize, -1);
231d77787f2SJonathan Schleifer        }
232d77787f2SJonathan Schleifer
233d77787f2SJonathan Schleifer      free (basedir);
234d77787f2SJonathan Schleifer      free (newname);
235d77787f2SJonathan Schleifer    }
236d77787f2SJonathan Schleifer  free (linkbuf);
237d77787f2SJonathan Schleifer
238d77787f2SJonathan Schleifer  return 0;
239d77787f2SJonathan Schleifer
240d77787f2SJonathan Schleifer/* An error reading image file. Release resources and return error code */
241d77787f2SJonathan Schleiferfile_error:
242d77787f2SJonathan Schleifer  free(stringtab);
243d77787f2SJonathan Schleifer  free(sec_hdrs);
244d77787f2SJonathan Schleifer  free(linkbuf);
245d77787f2SJonathan Schleifer  fclose(f);
246d77787f2SJonathan Schleifer
247d77787f2SJonathan Schleifer  return 1;
248d77787f2SJonathan Schleifer}
249d77787f2SJonathan Schleifer
250d77787f2SJonathan Schleifer/* Locate the binary which originated the contents of address ADDR. Return
251d77787f2SJonathan Schleifer   the name of the binary in *name (space is allocated by the caller)
252d77787f2SJonathan Schleifer   Returns 0 if a binary is successfully found, or 1 if an error occurs.  */
253d77787f2SJonathan Schleifer
254d77787f2SJonathan Schleiferstatic int
255d77787f2SJonathan Schleiferfind_binary_for_address (unw_word_t ip, char *name, size_t name_size)
256d77787f2SJonathan Schleifer{
257d77787f2SJonathan Schleifer#if defined(__linux) && (!UNW_REMOTE_ONLY)
258d77787f2SJonathan Schleifer  struct map_iterator mi;
259d77787f2SJonathan Schleifer  int found = 0;
260d77787f2SJonathan Schleifer  int pid = getpid ();
261d77787f2SJonathan Schleifer  unsigned long segbase, mapoff, hi;
262d77787f2SJonathan Schleifer
263d77787f2SJonathan Schleifer  maps_init (&mi, pid);
264d77787f2SJonathan Schleifer  while (maps_next (&mi, &segbase, &hi, &mapoff))
265d77787f2SJonathan Schleifer    if (ip >= segbase && ip < hi)
266d77787f2SJonathan Schleifer      {
267d77787f2SJonathan Schleifer        size_t len = strlen (mi.path);
268d77787f2SJonathan Schleifer
269d77787f2SJonathan Schleifer        if (len + 1 <= name_size)
270d77787f2SJonathan Schleifer          {
271d77787f2SJonathan Schleifer            memcpy (name, mi.path, len + 1);
272d77787f2SJonathan Schleifer            found = 1;
273d77787f2SJonathan Schleifer          }
274d77787f2SJonathan Schleifer        break;
275d77787f2SJonathan Schleifer      }
276d77787f2SJonathan Schleifer  maps_close (&mi);
277d77787f2SJonathan Schleifer  return !found;
278d77787f2SJonathan Schleifer#endif
279d77787f2SJonathan Schleifer
280d77787f2SJonathan Schleifer  return 1;
281d77787f2SJonathan Schleifer}
282d77787f2SJonathan Schleifer
283d77787f2SJonathan Schleifer/* Locate and/or try to load a debug_frame section for address ADDR.  Return
284d77787f2SJonathan Schleifer   pointer to debug frame descriptor, or zero if not found.  */
285d77787f2SJonathan Schleifer
286d77787f2SJonathan Schleiferstatic struct unw_debug_frame_list *
287d77787f2SJonathan Schleiferlocate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
288d77787f2SJonathan Schleifer                   unw_word_t start, unw_word_t end)
289d77787f2SJonathan Schleifer{
290d77787f2SJonathan Schleifer  struct unw_debug_frame_list *w, *fdesc = 0;
291d77787f2SJonathan Schleifer  char path[PATH_MAX];
292d77787f2SJonathan Schleifer  char *name = path;
293d77787f2SJonathan Schleifer  int err;
294d77787f2SJonathan Schleifer  char *buf;
295d77787f2SJonathan Schleifer  size_t bufsize;
296d77787f2SJonathan Schleifer
297d77787f2SJonathan Schleifer  /* First, see if we loaded this frame already.  */
298d77787f2SJonathan Schleifer
299d77787f2SJonathan Schleifer  for (w = as->debug_frames; w; w = w->next)
300d77787f2SJonathan Schleifer    {
301d77787f2SJonathan Schleifer      Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end);
302d77787f2SJonathan Schleifer      if (addr >= w->start && addr < w->end)
303d77787f2SJonathan Schleifer        return w;
304d77787f2SJonathan Schleifer    }
305d77787f2SJonathan Schleifer
306d77787f2SJonathan Schleifer  /* If the object name we receive is blank, there's still a chance of locating
307d77787f2SJonathan Schleifer     the file by parsing /proc/self/maps.  */
308d77787f2SJonathan Schleifer
309d77787f2SJonathan Schleifer  if (strcmp (dlname, "") == 0)
310d77787f2SJonathan Schleifer    {
311d77787f2SJonathan Schleifer      err = find_binary_for_address (addr, name, sizeof(path));
312d77787f2SJonathan Schleifer      if (err)
313d77787f2SJonathan Schleifer        {
314d77787f2SJonathan Schleifer          Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n",
315d77787f2SJonathan Schleifer                 (uint64_t) addr);
316d77787f2SJonathan Schleifer          return 0;
317d77787f2SJonathan Schleifer        }
318d77787f2SJonathan Schleifer    }
319d77787f2SJonathan Schleifer  else
320d77787f2SJonathan Schleifer    name = (char*) dlname;
321d77787f2SJonathan Schleifer
322d77787f2SJonathan Schleifer  err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
323d77787f2SJonathan Schleifer
324d77787f2SJonathan Schleifer  if (!err)
325d77787f2SJonathan Schleifer    {
326d77787f2SJonathan Schleifer      fdesc = malloc (sizeof (struct unw_debug_frame_list));
327d77787f2SJonathan Schleifer
328d77787f2SJonathan Schleifer      fdesc->start = start;
329d77787f2SJonathan Schleifer      fdesc->end = end;
330d77787f2SJonathan Schleifer      fdesc->debug_frame = buf;
331d77787f2SJonathan Schleifer      fdesc->debug_frame_size = bufsize;
332d77787f2SJonathan Schleifer      fdesc->index = NULL;
333d77787f2SJonathan Schleifer      fdesc->next = as->debug_frames;
334d77787f2SJonathan Schleifer
335d77787f2SJonathan Schleifer      as->debug_frames = fdesc;
336d77787f2SJonathan Schleifer    }
337d77787f2SJonathan Schleifer
338d77787f2SJonathan Schleifer  return fdesc;
339d77787f2SJonathan Schleifer}
340d77787f2SJonathan Schleifer
341d77787f2SJonathan Schleiferstruct debug_frame_tab
342d77787f2SJonathan Schleifer  {
343d77787f2SJonathan Schleifer    struct table_entry *tab;
344d77787f2SJonathan Schleifer    uint32_t length;
345d77787f2SJonathan Schleifer    uint32_t size;
346d77787f2SJonathan Schleifer  };
347d77787f2SJonathan Schleifer
348d77787f2SJonathan Schleiferstatic void
349d77787f2SJonathan Schleiferdebug_frame_tab_append (struct debug_frame_tab *tab,
350d77787f2SJonathan Schleifer                        unw_word_t fde_offset, unw_word_t start_ip)
351d77787f2SJonathan Schleifer{
352d77787f2SJonathan Schleifer  unsigned int length = tab->length;
353d77787f2SJonathan Schleifer
354d77787f2SJonathan Schleifer  if (length == tab->size)
355d77787f2SJonathan Schleifer    {
356d77787f2SJonathan Schleifer      tab->size *= 2;
357d77787f2SJonathan Schleifer      tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
358d77787f2SJonathan Schleifer    }
359d77787f2SJonathan Schleifer
360d77787f2SJonathan Schleifer  tab->tab[length].fde_offset = fde_offset;
361d77787f2SJonathan Schleifer  tab->tab[length].start_ip_offset = start_ip;
362d77787f2SJonathan Schleifer
363d77787f2SJonathan Schleifer  tab->length = length + 1;
364d77787f2SJonathan Schleifer}
365d77787f2SJonathan Schleifer
366d77787f2SJonathan Schleiferstatic void
367d77787f2SJonathan Schleiferdebug_frame_tab_shrink (struct debug_frame_tab *tab)
368d77787f2SJonathan Schleifer{
369d77787f2SJonathan Schleifer  if (tab->size > tab->length)
370d77787f2SJonathan Schleifer    {
371d77787f2SJonathan Schleifer      tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length);
372d77787f2SJonathan Schleifer      tab->size = tab->length;
373d77787f2SJonathan Schleifer    }
374d77787f2SJonathan Schleifer}
375d77787f2SJonathan Schleifer
376d77787f2SJonathan Schleiferstatic int
377d77787f2SJonathan Schleiferdebug_frame_tab_compare (const void *a, const void *b)
378d77787f2SJonathan Schleifer{
379d77787f2SJonathan Schleifer  const struct table_entry *fa = a, *fb = b;
380d77787f2SJonathan Schleifer
381d77787f2SJonathan Schleifer  if (fa->start_ip_offset > fb->start_ip_offset)
382d77787f2SJonathan Schleifer    return 1;
383d77787f2SJonathan Schleifer  else if (fa->start_ip_offset < fb->start_ip_offset)
384d77787f2SJonathan Schleifer    return -1;
385d77787f2SJonathan Schleifer  else
386d77787f2SJonathan Schleifer    return 0;
387d77787f2SJonathan Schleifer}
388d77787f2SJonathan Schleifer
389d77787f2SJonathan SchleiferPROTECTED int
390d77787f2SJonathan Schleiferdwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
391d77787f2SJonathan Schleifer                        unw_word_t segbase, const char* obj_name,
392d77787f2SJonathan Schleifer                        unw_word_t start, unw_word_t end)
393d77787f2SJonathan Schleifer{
394d77787f2SJonathan Schleifer  unw_dyn_info_t *di;
395d77787f2SJonathan Schleifer  struct unw_debug_frame_list *fdesc = 0;
396d77787f2SJonathan Schleifer  unw_accessors_t *a;
397d77787f2SJonathan Schleifer  unw_word_t addr;
398d77787f2SJonathan Schleifer
399d77787f2SJonathan Schleifer  Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
400d77787f2SJonathan Schleifer  di = di_debug;
401d77787f2SJonathan Schleifer
402d77787f2SJonathan Schleifer  fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
403d77787f2SJonathan Schleifer
404d77787f2SJonathan Schleifer  if (!fdesc)
405d77787f2SJonathan Schleifer    {
406d77787f2SJonathan Schleifer      Debug (15, "couldn't load .debug_frame\n");
407d77787f2SJonathan Schleifer      return found;
408d77787f2SJonathan Schleifer    }
409d77787f2SJonathan Schleifer  else
410d77787f2SJonathan Schleifer    {
411d77787f2SJonathan Schleifer      char *buf;
412d77787f2SJonathan Schleifer      size_t bufsize;
413d77787f2SJonathan Schleifer      unw_word_t item_start, item_end = 0;
414d77787f2SJonathan Schleifer      uint32_t u32val = 0;
415d77787f2SJonathan Schleifer      uint64_t cie_id = 0;
416d77787f2SJonathan Schleifer      struct debug_frame_tab tab;
417d77787f2SJonathan Schleifer
418d77787f2SJonathan Schleifer      Debug (15, "loaded .debug_frame\n");
419d77787f2SJonathan Schleifer
420d77787f2SJonathan Schleifer      buf = fdesc->debug_frame;
421d77787f2SJonathan Schleifer      bufsize = fdesc->debug_frame_size;
422d77787f2SJonathan Schleifer
423d77787f2SJonathan Schleifer      if (bufsize == 0)
424d77787f2SJonathan Schleifer       {
425d77787f2SJonathan Schleifer         Debug (15, "zero-length .debug_frame\n");
426d77787f2SJonathan Schleifer         return found;
427d77787f2SJonathan Schleifer       }
428d77787f2SJonathan Schleifer
429d77787f2SJonathan Schleifer      /* Now create a binary-search table, if it does not already exist.  */
430d77787f2SJonathan Schleifer      if (!fdesc->index)
431d77787f2SJonathan Schleifer       {
432d77787f2SJonathan Schleifer         addr = (unw_word_t) (uintptr_t) buf;
433d77787f2SJonathan Schleifer
434d77787f2SJonathan Schleifer         a = unw_get_accessors (unw_local_addr_space);
435d77787f2SJonathan Schleifer
436d77787f2SJonathan Schleifer         /* Find all FDE entries in debug_frame, and make into a sorted
437d77787f2SJonathan Schleifer            index.  */
438d77787f2SJonathan Schleifer
439d77787f2SJonathan Schleifer         tab.length = 0;
440d77787f2SJonathan Schleifer         tab.size = 16;
441d77787f2SJonathan Schleifer         tab.tab = calloc (tab.size, sizeof (struct table_entry));
442d77787f2SJonathan Schleifer
443d77787f2SJonathan Schleifer         while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
444d77787f2SJonathan Schleifer           {
445d77787f2SJonathan Schleifer             uint64_t id_for_cie;
446d77787f2SJonathan Schleifer             item_start = addr;
447d77787f2SJonathan Schleifer
448d77787f2SJonathan Schleifer             dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
449d77787f2SJonathan Schleifer
450d77787f2SJonathan Schleifer             if (u32val == 0)
451d77787f2SJonathan Schleifer               break;
452d77787f2SJonathan Schleifer             else if (u32val != 0xffffffff)
453d77787f2SJonathan Schleifer               {
454d77787f2SJonathan Schleifer                 uint32_t cie_id32 = 0;
455d77787f2SJonathan Schleifer                 item_end = addr + u32val;
456d77787f2SJonathan Schleifer                 dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
457d77787f2SJonathan Schleifer                                NULL);
458d77787f2SJonathan Schleifer                 cie_id = cie_id32;
459d77787f2SJonathan Schleifer                 id_for_cie = 0xffffffff;
460d77787f2SJonathan Schleifer               }
461d77787f2SJonathan Schleifer             else
462d77787f2SJonathan Schleifer               {
463d77787f2SJonathan Schleifer                 uint64_t u64val = 0;
464d77787f2SJonathan Schleifer                 /* Extended length.  */
465d77787f2SJonathan Schleifer                 dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
466d77787f2SJonathan Schleifer                 item_end = addr + u64val;
467d77787f2SJonathan Schleifer
468d77787f2SJonathan Schleifer                 dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
469d77787f2SJonathan Schleifer                 id_for_cie = 0xffffffffffffffffull;
470d77787f2SJonathan Schleifer               }
471d77787f2SJonathan Schleifer
472d77787f2SJonathan Schleifer             /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
473d77787f2SJonathan Schleifer
474d77787f2SJonathan Schleifer             if (cie_id == id_for_cie)
475d77787f2SJonathan Schleifer               ;
476d77787f2SJonathan Schleifer             /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
477d77787f2SJonathan Schleifer             else
478d77787f2SJonathan Schleifer               {
479d77787f2SJonathan Schleifer                 unw_word_t fde_addr = item_start;
480d77787f2SJonathan Schleifer                 unw_proc_info_t this_pi;
481d77787f2SJonathan Schleifer                 int err;
482d77787f2SJonathan Schleifer
483d77787f2SJonathan Schleifer                 /*Debug (1, "Found FDE at %.8x\n", item_start);*/
484d77787f2SJonathan Schleifer
485d77787f2SJonathan Schleifer                 err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
486d77787f2SJonathan Schleifer                                                         a, &fde_addr,
487d77787f2SJonathan Schleifer                                                         &this_pi,
488d77787f2SJonathan Schleifer                                                         (uintptr_t) buf, 0, 1,
489d77787f2SJonathan Schleifer                                                         NULL);
490d77787f2SJonathan Schleifer                 if (err == 0)
491d77787f2SJonathan Schleifer                   {
492d77787f2SJonathan Schleifer                     Debug (15, "start_ip = %lx, end_ip = %lx\n",
493d77787f2SJonathan Schleifer                            (long) this_pi.start_ip, (long) this_pi.end_ip);
494d77787f2SJonathan Schleifer                     debug_frame_tab_append (&tab,
495d77787f2SJonathan Schleifer                                             item_start - (unw_word_t) (uintptr_t) buf,
496d77787f2SJonathan Schleifer                                             this_pi.start_ip);
497d77787f2SJonathan Schleifer                   }
498d77787f2SJonathan Schleifer                 /*else
499d77787f2SJonathan Schleifer                   Debug (1, "FDE parse failed\n");*/
500d77787f2SJonathan Schleifer               }
501d77787f2SJonathan Schleifer
502d77787f2SJonathan Schleifer             addr = item_end;
503d77787f2SJonathan Schleifer           }
504d77787f2SJonathan Schleifer
505d77787f2SJonathan Schleifer         debug_frame_tab_shrink (&tab);
506d77787f2SJonathan Schleifer         qsort (tab.tab, tab.length, sizeof (struct table_entry),
507d77787f2SJonathan Schleifer                debug_frame_tab_compare);
508d77787f2SJonathan Schleifer         /* for (i = 0; i < tab.length; i++)
509d77787f2SJonathan Schleifer            {
510d77787f2SJonathan Schleifer            fprintf (stderr, "ip %x, fde offset %x\n",
511d77787f2SJonathan Schleifer            (int) tab.tab[i].start_ip_offset,
512d77787f2SJonathan Schleifer            (int) tab.tab[i].fde_offset);
513d77787f2SJonathan Schleifer            }*/
514d77787f2SJonathan Schleifer         fdesc->index = tab.tab;
515d77787f2SJonathan Schleifer         fdesc->index_size = tab.length;
516d77787f2SJonathan Schleifer       }
517d77787f2SJonathan Schleifer
518d77787f2SJonathan Schleifer      di->format = UNW_INFO_FORMAT_TABLE;
519d77787f2SJonathan Schleifer      di->start_ip = fdesc->start;
520d77787f2SJonathan Schleifer      di->end_ip = fdesc->end;
521d77787f2SJonathan Schleifer      di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
522d77787f2SJonathan Schleifer      di->u.ti.table_data = (unw_word_t *) fdesc;
523d77787f2SJonathan Schleifer      di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
524d77787f2SJonathan Schleifer      di->u.ti.segbase = segbase;
525d77787f2SJonathan Schleifer
526d77787f2SJonathan Schleifer      found = 1;
527d77787f2SJonathan Schleifer      Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
528d77787f2SJonathan Schleifer            "gp=0x%lx, table_data=0x%lx\n",
529d77787f2SJonathan Schleifer            (char *) (uintptr_t) di->u.ti.name_ptr,
530d77787f2SJonathan Schleifer            (long) di->u.ti.segbase, (long) di->u.ti.table_len,
531d77787f2SJonathan Schleifer            (long) di->gp, (long) di->u.ti.table_data);
532d77787f2SJonathan Schleifer    }
533d77787f2SJonathan Schleifer  return found;
534d77787f2SJonathan Schleifer}
535d77787f2SJonathan Schleifer
536d77787f2SJonathan Schleifer#endif /* CONFIG_DEBUG_FRAME */
537d77787f2SJonathan Schleifer
538d77787f2SJonathan Schleifer#ifndef UNW_REMOTE_ONLY
539d77787f2SJonathan Schleifer
540d77787f2SJonathan Schleiferstatic int
541d77787f2SJonathan Schleiferdwarf_search_fde_in_unwind_table (unw_addr_space_t as, unw_word_t ip,
542d77787f2SJonathan Schleifer                                  unw_word_t segbase, size_t table_len,
543d77787f2SJonathan Schleifer                                  const struct table_entry *table,
544d77787f2SJonathan Schleifer                                  unw_word_t debug_frame_base,
545d77787f2SJonathan Schleifer                                  unw_word_t *fde_addr,
546d77787f2SJonathan Schleifer                                  void *arg)
547d77787f2SJonathan Schleifer{
548d77787f2SJonathan Schleifer  const struct table_entry *e = NULL;
549d77787f2SJonathan Schleifer  unw_accessors_t *a;
550d77787f2SJonathan Schleifer#ifndef UNW_LOCAL_ONLY
551d77787f2SJonathan Schleifer  struct table_entry ent;
552d77787f2SJonathan Schleifer#endif
553d77787f2SJonathan Schleifer  int ret;
554d77787f2SJonathan Schleifer
555d77787f2SJonathan Schleifer  Debug(15, "dwarf_search_fde_in_unwind_table: ip=0x%lx, segbase=%lx, "
556d77787f2SJonathan Schleifer            "table_len=%zu, table=%p, debug_frame_base=%lx",
557d77787f2SJonathan Schleifer        ip, segbase, table_len, table, debug_frame_base);
558d77787f2SJonathan Schleifer
559d77787f2SJonathan Schleifer  a = unw_get_accessors (as);
560d77787f2SJonathan Schleifer
561d77787f2SJonathan Schleifer#ifndef UNW_REMOTE_ONLY
562d77787f2SJonathan Schleifer  if (as == unw_local_addr_space)
563d77787f2SJonathan Schleifer    {
564d77787f2SJonathan Schleifer      e = lookup (table, table_len, ip - segbase);
565d77787f2SJonathan Schleifer    }
566d77787f2SJonathan Schleifer  else
567d77787f2SJonathan Schleifer#endif
568d77787f2SJonathan Schleifer    {
569d77787f2SJonathan Schleifer#ifndef UNW_LOCAL_ONLY
570d77787f2SJonathan Schleifer      if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
571d77787f2SJonathan Schleifer                ip - segbase, &ent, arg)) < 0)
572d77787f2SJonathan Schleifer    return ret;
573d77787f2SJonathan Schleifer      if (ret)
574d77787f2SJonathan Schleifer    e = &ent;
575d77787f2SJonathan Schleifer      else
576d77787f2SJonathan Schleifer    e = NULL;	/* no info found */
577d77787f2SJonathan Schleifer#endif
578d77787f2SJonathan Schleifer    }
579d77787f2SJonathan Schleifer  if (!e)
580d77787f2SJonathan Schleifer    {
581d77787f2SJonathan Schleifer      Debug (1, "IP %x: no explicit unwind info found\n",
582d77787f2SJonathan Schleifer         (int) ip);
583d77787f2SJonathan Schleifer      /* IP is inside this table's range, but there is no explicit
584d77787f2SJonathan Schleifer     unwind info.  */
585d77787f2SJonathan Schleifer      return -UNW_ENOINFO;
586d77787f2SJonathan Schleifer    }
587d77787f2SJonathan Schleifer
588d77787f2SJonathan Schleifer  Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
589d77787f2SJonathan Schleifer     (long) ip, (long) (e->start_ip_offset));
590d77787f2SJonathan Schleifer
591d77787f2SJonathan Schleifer  if (debug_frame_base)
592d77787f2SJonathan Schleifer    *fde_addr = e->fde_offset + debug_frame_base;
593d77787f2SJonathan Schleifer  else
594d77787f2SJonathan Schleifer    *fde_addr = e->fde_offset + segbase;
595d77787f2SJonathan Schleifer
596d77787f2SJonathan Schleifer  Debug (1, "e->fde_offset = %x, segbase = %x, debug_frame_base = %x, "
597d77787f2SJonathan Schleifer        "fde_addr = %x\n", (int) e->fde_offset, (int) segbase,
598d77787f2SJonathan Schleifer        (int) debug_frame_base, (int) fde_addr);
599d77787f2SJonathan Schleifer
600d77787f2SJonathan Schleifer  return 0;
601d77787f2SJonathan Schleifer}
602d77787f2SJonathan Schleifer
603d77787f2SJonathan Schleifer
604d77787f2SJonathan Schleifer/* Searches for FDE for specific ip in eh_frame_hdr.
605d77787f2SJonathan Schleifer   Returns 0 if success. */
606d77787f2SJonathan Schleiferstatic int
607d77787f2SJonathan Schleifersearch_fde_in_eh_frame(unw_word_t ip, unw_word_t hdr_addr, unw_word_t gp,
608d77787f2SJonathan Schleifer                       unw_word_t eh_frame_end, unw_word_t *fde_addr,
609d77787f2SJonathan Schleifer                       int need_unwind_info, void *arg,
610d77787f2SJonathan Schleifer                       const char * name)
611d77787f2SJonathan Schleifer{
612d77787f2SJonathan Schleifer  unw_accessors_t *a;
613d77787f2SJonathan Schleifer  unw_word_t addr, eh_frame_start, fde_count;
614d77787f2SJonathan Schleifer  int ret;
615d77787f2SJonathan Schleifer  struct dwarf_eh_frame_hdr *hdr = (struct dwarf_eh_frame_hdr *)hdr_addr;
616d77787f2SJonathan Schleifer
617d77787f2SJonathan Schleifer  if (hdr->version != DW_EH_VERSION)
618d77787f2SJonathan Schleifer	{
619d77787f2SJonathan Schleifer	  Debug (1, "table `%s' has unexpected version %d\n",
620d77787f2SJonathan Schleifer		 name, hdr->version);
621d77787f2SJonathan Schleifer	  return -UNW_ENOINFO;
622d77787f2SJonathan Schleifer	}
623d77787f2SJonathan Schleifer
624d77787f2SJonathan Schleifer  a = unw_get_accessors (unw_local_addr_space);
625d77787f2SJonathan Schleifer  addr = (unw_word_t) (uintptr_t) (hdr + 1);
626d77787f2SJonathan Schleifer
627d77787f2SJonathan Schleifer  /* (Optionally) read eh_frame_ptr: */
628d77787f2SJonathan Schleifer  if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
629d77787f2SJonathan Schleifer					                     &addr, hdr->eh_frame_ptr_enc, gp, 0,
630d77787f2SJonathan Schleifer                                         &eh_frame_start, NULL)) < 0)
631d77787f2SJonathan Schleifer	return ret;
632d77787f2SJonathan Schleifer
633d77787f2SJonathan Schleifer  /* (Optionally) read fde_count: */
634d77787f2SJonathan Schleifer  if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
635d77787f2SJonathan Schleifer                                         &addr, hdr->fde_count_enc, gp, 0,
636d77787f2SJonathan Schleifer                                         &fde_count, NULL)) < 0)
637d77787f2SJonathan Schleifer	return ret;
638d77787f2SJonathan Schleifer
639d77787f2SJonathan Schleifer  if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
640d77787f2SJonathan Schleifer	{
641d77787f2SJonathan Schleifer      int err;
642d77787f2SJonathan Schleifer
643d77787f2SJonathan Schleifer	  /* If there is no search table or it has an unsupported
644d77787f2SJonathan Schleifer	     encoding, fall back on linear search.  */
645d77787f2SJonathan Schleifer	  if (hdr->table_enc == DW_EH_PE_omit)
646d77787f2SJonathan Schleifer	    Debug (4, "table `%s' lacks search table; doing linear search\n",
647d77787f2SJonathan Schleifer		   name);
648d77787f2SJonathan Schleifer	  else
649d77787f2SJonathan Schleifer	    Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
650d77787f2SJonathan Schleifer		   name, hdr->table_enc);
651d77787f2SJonathan Schleifer
652d77787f2SJonathan Schleifer	  if (hdr->fde_count_enc == DW_EH_PE_omit)
653d77787f2SJonathan Schleifer	    fde_count = ~0UL;
654d77787f2SJonathan Schleifer	  if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
655d77787f2SJonathan Schleifer	    abort ();
656d77787f2SJonathan Schleifer
657d77787f2SJonathan Schleifer	  /* XXX we know how to build a local binary search table for
658d77787f2SJonathan Schleifer	     .debug_frame, so we could do that here too.  */
659d77787f2SJonathan Schleifer	  return  linear_search (unw_local_addr_space, ip,
660d77787f2SJonathan Schleifer                             eh_frame_start, eh_frame_end, fde_count,
661d77787f2SJonathan Schleifer                             fde_addr, need_unwind_info, NULL);
662d77787f2SJonathan Schleifer	}
663d77787f2SJonathan Schleifer  else
664d77787f2SJonathan Schleifer	{
665d77787f2SJonathan Schleifer      int err;
666d77787f2SJonathan Schleifer
667d77787f2SJonathan Schleifer      size_t table_len = (fde_count * sizeof (struct table_entry));
668d77787f2SJonathan Schleifer	  /* For the binary-search table in the eh_frame_hdr, data-relative
669d77787f2SJonathan Schleifer	     means relative to the start of that section... */
670d77787f2SJonathan Schleifer	  unw_word_t sbase = (unw_word_t) (uintptr_t) hdr;
671d77787f2SJonathan Schleifer
672d77787f2SJonathan Schleifer	  Debug (15, "found table `%s': sbase=0x%lx, len=%lu, gp=0x%lx, "
673d77787f2SJonathan Schleifer		 "table_data=0x%lx\n", (char *) (uintptr_t) name,
674d77787f2SJonathan Schleifer		 (long) sbase, (long) table_len,
675d77787f2SJonathan Schleifer		 (long) gp, (long) addr);
676d77787f2SJonathan Schleifer
677d77787f2SJonathan Schleifer      return dwarf_search_fde_in_unwind_table (unw_local_addr_space, ip,
678d77787f2SJonathan Schleifer                                               sbase, table_len,
679d77787f2SJonathan Schleifer                                               (const struct table_entry*)addr, 0,
680d77787f2SJonathan Schleifer                                               fde_addr, arg);
681d77787f2SJonathan Schleifer	}
682d77787f2SJonathan Schleifer}
683d77787f2SJonathan Schleifer
684d77787f2SJonathan Schleifer#ifdef HAVE_DL_ITERATE_PHDR
685d77787f2SJonathan Schleifer
686d77787f2SJonathan Schleifer/* ptr is a pointer to a dwarf_callback_data structure and, on entry,
687d77787f2SJonathan Schleifer   member ip contains the instruction-pointer we're looking
688d77787f2SJonathan Schleifer   for.  */
689d77787f2SJonathan SchleiferHIDDEN int
690d77787f2SJonathan Schleiferdwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
691d77787f2SJonathan Schleifer{
692d77787f2SJonathan Schleifer  struct dwarf_callback_data *cb_data = ptr;
693d77787f2SJonathan Schleifer  const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
694d77787f2SJonathan Schleifer  unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
695d77787f2SJonathan Schleifer  Elf_W(Addr) load_base, max_load_addr = 0;
696d77787f2SJonathan Schleifer  int ret, need_unwind_info = cb_data->need_unwind_info;
697d77787f2SJonathan Schleifer  struct dwarf_eh_frame_hdr *hdr;
698d77787f2SJonathan Schleifer  unw_accessors_t *a;
699d77787f2SJonathan Schleifer  long n;
700d77787f2SJonathan Schleifer  int found = 0;
701d77787f2SJonathan Schleifer#ifdef CONFIG_DEBUG_FRAME
702d77787f2SJonathan Schleifer  unw_word_t start, end;
703d77787f2SJonathan Schleifer#endif /* CONFIG_DEBUG_FRAME*/
704d77787f2SJonathan Schleifer
705d77787f2SJonathan Schleifer  ip = cb_data->ip;
706d77787f2SJonathan Schleifer
707d77787f2SJonathan Schleifer  /* Make sure struct dl_phdr_info is at least as big as we need.  */
708d77787f2SJonathan Schleifer  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
709d77787f2SJonathan Schleifer             + sizeof (info->dlpi_phnum))
710d77787f2SJonathan Schleifer    return -1;
711d77787f2SJonathan Schleifer
712d77787f2SJonathan Schleifer  Debug (15, "checking %s, base=0x%lx)\n",
713d77787f2SJonathan Schleifer         info->dlpi_name, (long) info->dlpi_addr);
714d77787f2SJonathan Schleifer
715d77787f2SJonathan Schleifer  phdr = info->dlpi_phdr;
716d77787f2SJonathan Schleifer  load_base = info->dlpi_addr;
717d77787f2SJonathan Schleifer  p_text = NULL;
718d77787f2SJonathan Schleifer  p_eh_hdr = NULL;
719d77787f2SJonathan Schleifer  p_dynamic = NULL;
720d77787f2SJonathan Schleifer
721d77787f2SJonathan Schleifer  /* See if PC falls into one of the loaded segments.  Find the
722d77787f2SJonathan Schleifer     eh-header segment at the same time.  */
723d77787f2SJonathan Schleifer  for (n = info->dlpi_phnum; --n >= 0; phdr++)
724d77787f2SJonathan Schleifer    {
725d77787f2SJonathan Schleifer      if (phdr->p_type == PT_LOAD)
726d77787f2SJonathan Schleifer        {
727d77787f2SJonathan Schleifer          Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
728d77787f2SJonathan Schleifer
729d77787f2SJonathan Schleifer          if (ip >= vaddr && ip < vaddr + phdr->p_memsz)
730d77787f2SJonathan Schleifer            p_text = phdr;
731d77787f2SJonathan Schleifer
732d77787f2SJonathan Schleifer          if (vaddr + phdr->p_filesz > max_load_addr)
733d77787f2SJonathan Schleifer            max_load_addr = vaddr + phdr->p_filesz;
734d77787f2SJonathan Schleifer        }
735d77787f2SJonathan Schleifer      else if (phdr->p_type == PT_GNU_EH_FRAME)
736d77787f2SJonathan Schleifer        p_eh_hdr = phdr;
737d77787f2SJonathan Schleifer      else if (phdr->p_type == PT_DYNAMIC)
738d77787f2SJonathan Schleifer        p_dynamic = phdr;
739d77787f2SJonathan Schleifer    }
740d77787f2SJonathan Schleifer
741d77787f2SJonathan Schleifer  if (!p_text)
742d77787f2SJonathan Schleifer    return 0;
743d77787f2SJonathan Schleifer
744d77787f2SJonathan Schleifer  if (p_eh_hdr)
745d77787f2SJonathan Schleifer    {
746d77787f2SJonathan Schleifer      if (p_dynamic)
747d77787f2SJonathan Schleifer        {
748d77787f2SJonathan Schleifer          /* For dynamicly linked executables and shared libraries,
749d77787f2SJonathan Schleifer             DT_PLTGOT is the value that data-relative addresses are
750d77787f2SJonathan Schleifer             relative to for that object.  We call this the "gp".  */
751d77787f2SJonathan Schleifer          Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
752d77787f2SJonathan Schleifer          for (; dyn->d_tag != DT_NULL; ++dyn)
753d77787f2SJonathan Schleifer            if (dyn->d_tag == DT_PLTGOT)
754d77787f2SJonathan Schleifer              {
755d77787f2SJonathan Schleifer                /* Assume that _DYNAMIC is writable and GLIBC has
756d77787f2SJonathan Schleifer                   relocated it (true for x86 at least).  */
757d77787f2SJonathan Schleifer                cb_data->gp = dyn->d_un.d_ptr;
758d77787f2SJonathan Schleifer                break;
759d77787f2SJonathan Schleifer              }
760d77787f2SJonathan Schleifer        }
761d77787f2SJonathan Schleifer      else
762d77787f2SJonathan Schleifer        /* Otherwise this is a static executable with no _DYNAMIC.  Assume
763d77787f2SJonathan Schleifer           that data-relative addresses are relative to 0, i.e.,
764d77787f2SJonathan Schleifer           absolute.  */
765d77787f2SJonathan Schleifer        cb_data->gp = 0;
766d77787f2SJonathan Schleifer
767d77787f2SJonathan Schleifer      eh_frame_end = (unw_word_t)max_load_addr;   // Can we do better?
768d77787f2SJonathan Schleifer      ret = search_fde_in_eh_frame(ip, (unw_word_t)(p_eh_hdr->p_vaddr + load_base),
769d77787f2SJonathan Schleifer                                   cb_data->gp, eh_frame_end, &cb_data->fde_addr,
770d77787f2SJonathan Schleifer                                   cb_data->need_unwind_info, cb_data->arg, info->dlpi_name);
771d77787f2SJonathan Schleifer      if (ret < 0)
772d77787f2SJonathan Schleifer        return ret;
773d77787f2SJonathan Schleifer
774d77787f2SJonathan Schleifer      cb_data->fde_base = 0;
775d77787f2SJonathan Schleifer      cb_data->ip_offset = 0;
776d77787f2SJonathan Schleifer
777d77787f2SJonathan Schleifer      return 1;
778d77787f2SJonathan Schleifer    }
779d77787f2SJonathan Schleifer
780d77787f2SJonathan Schleifer#ifdef CONFIG_DEBUG_FRAME
781d77787f2SJonathan Schleifer  found = dwarf_find_debug_frame (found, &cb_data->di_debug, info, ip);
782d77787f2SJonathan Schleifer#endif  /* CONFIG_DEBUG_FRAME */
783d77787f2SJonathan Schleifer
784d77787f2SJonathan Schleifer  return found;
785d77787f2SJonathan Schleifer}
786d77787f2SJonathan Schleifer
787d77787f2SJonathan Schleiferstatic int
788d77787f2SJonathan Schleiferfind_proc_fde (unw_word_t ip, unw_word_t *fde_addr,
789d77787f2SJonathan Schleifer               unw_word_t *gp, unw_word_t *fde_base,
790d77787f2SJonathan Schleifer               unw_word_t *ip_offset, void *arg) {
791d77787f2SJonathan Schleifer  struct dwarf_callback_data cb_data;
792d77787f2SJonathan Schleifer  intrmask_t saved_mask;
793d77787f2SJonathan Schleifer  int ret;
794d77787f2SJonathan Schleifer
795d77787f2SJonathan Schleifer  memset (&cb_data, 0, sizeof (cb_data));
796d77787f2SJonathan Schleifer  cb_data.ip = ip;
797d77787f2SJonathan Schleifer  cb_data.arg = arg;
798d77787f2SJonathan Schleifer
799d77787f2SJonathan Schleifer  SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
800d77787f2SJonathan Schleifer  ret = dl_iterate_phdr (dwarf_callback, &cb_data);
801d77787f2SJonathan Schleifer  SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
802d77787f2SJonathan Schleifer
803d77787f2SJonathan Schleifer  if (ret < 0)
804d77787f2SJonathan Schleifer    return ret;
805d77787f2SJonathan Schleifer
806d77787f2SJonathan Schleifer  if (ret == 0)
807d77787f2SJonathan Schleifer    {
808d77787f2SJonathan Schleifer      ret = -UNW_ENOINFO;
809d77787f2SJonathan Schleifer      return ret;
810d77787f2SJonathan Schleifer    }
811d77787f2SJonathan Schleifer
812d77787f2SJonathan Schleifer  *fde_addr = cb_data.fde_addr;
813d77787f2SJonathan Schleifer  *gp = cb_data.gp;
814d77787f2SJonathan Schleifer  *fde_base = cb_data.fde_base;
815d77787f2SJonathan Schleifer  *ip_offset = cb_data.ip_offset;
816d77787f2SJonathan Schleifer
817d77787f2SJonathan Schleifer  return 0;
818d77787f2SJonathan Schleifer}
819d77787f2SJonathan Schleifer
820d77787f2SJonathan Schleifer#else // HAVE_DL_ITERATE_PHDR
821d77787f2SJonathan Schleifer
822d77787f2SJonathan Schleiferstatic int
823d77787f2SJonathan Schleiferfind_proc_fde(unw_word_t ip, unw_word_t *fde_addr,
824d77787f2SJonathan Schleifer              unw_word_t *gp, unw_word_t *fde_base,
825d77787f2SJonathan Schleifer              unw_word_t *ip_offset, void *arg) {
826d77787f2SJonathan Schleifer  Dl_amd64_unwindinfo dlef;
827d77787f2SJonathan Schleifer  void* data;
828d77787f2SJonathan Schleifer  void* data_end;
829d77787f2SJonathan Schleifer  int fp_enc, fc_enc, ft_enc;
830d77787f2SJonathan Schleifer  unsigned char *pi, *pj;
831d77787f2SJonathan Schleifer  ptrdiff_t reloc;
832d77787f2SJonathan Schleifer  uintptr_t base;
833d77787f2SJonathan Schleifer  int ret;
834d77787f2SJonathan Schleifer
835d77787f2SJonathan Schleifer  dlef.dlui_version = 1;
836d77787f2SJonathan Schleifer
837d77787f2SJonathan Schleifer  /* Locate the appropiate exception_range_entry table first */
838d77787f2SJonathan Schleifer  if (0 == dlamd64getunwind((void*)ip, &dlef)) {
839d77787f2SJonathan Schleifer    return -UNW_ENOINFO;
840d77787f2SJonathan Schleifer  }
841d77787f2SJonathan Schleifer
842d77787f2SJonathan Schleifer  /*
843d77787f2SJonathan Schleifer   * you now know size and position of block of data needed for
844d77787f2SJonathan Schleifer   * binary search ??REMOTE??
845d77787f2SJonathan Schleifer   */
846d77787f2SJonathan Schleifer  data = dlef.dlui_unwindstart;
847d77787f2SJonathan Schleifer  if (0 == data)
848d77787f2SJonathan Schleifer  	return -UNW_ENOINFO;
849d77787f2SJonathan Schleifer
850d77787f2SJonathan Schleifer  base = (uintptr_t)data;
851d77787f2SJonathan Schleifer  data_end = dlef.dlui_unwindend;
852d77787f2SJonathan Schleifer  reloc = 0;
853d77787f2SJonathan Schleifer  /* ??REMOTE?? */
854d77787f2SJonathan Schleifer
855d77787f2SJonathan Schleifer  *gp = 0;
856d77787f2SJonathan Schleifer  *fde_base = 0;
857d77787f2SJonathan Schleifer  *ip_offset = 0;
858d77787f2SJonathan Schleifer
859d77787f2SJonathan Schleifer  return search_fde_in_eh_frame(ip, (unw_word_t)data, 0,
860d77787f2SJonathan Schleifer                                (unw_word_t)data_end, fde_addr, arg, 0,
861d77787f2SJonathan Schleifer                                dlef.dlui_objname);
862d77787f2SJonathan Schleifer}
863d77787f2SJonathan Schleifer
864d77787f2SJonathan Schleifer#endif // HAVE_DL_ITERATE_PHDR
865d77787f2SJonathan Schleifer
866d77787f2SJonathan SchleiferHIDDEN int
867d77787f2SJonathan Schleiferdwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
868d77787f2SJonathan Schleifer                      unw_proc_info_t *pi, int need_unwind_info, void *arg)
869d77787f2SJonathan Schleifer{
870d77787f2SJonathan Schleifer  struct dwarf_callback_data cb_data;
871d77787f2SJonathan Schleifer  intrmask_t saved_mask;
872d77787f2SJonathan Schleifer  int ret;
873d77787f2SJonathan Schleifer  unw_word_t fde_addr;
874d77787f2SJonathan Schleifer  unw_word_t gp;
875d77787f2SJonathan Schleifer  unw_word_t fde_base;
876d77787f2SJonathan Schleifer  unw_word_t ip_offset;
877d77787f2SJonathan Schleifer  unw_accessors_t *a;
878d77787f2SJonathan Schleifer
879d77787f2SJonathan Schleifer  Debug (14, "looking for IP=0x%lx\n", (long) ip);
880d77787f2SJonathan Schleifer
881d77787f2SJonathan Schleifer  ret = find_proc_fde (ip, &fde_addr, &gp, &fde_base, &ip_offset, arg);
882d77787f2SJonathan Schleifer  if (ret < 0)
883d77787f2SJonathan Schleifer    {
884d77787f2SJonathan Schleifer      Debug (14, "IP=0x%lx not found\n", (long) ip);
885d77787f2SJonathan Schleifer      return ret;
886d77787f2SJonathan Schleifer    }
887d77787f2SJonathan Schleifer
888d77787f2SJonathan Schleifer  pi->gp = gp;
889d77787f2SJonathan Schleifer
890d77787f2SJonathan Schleifer  a = unw_get_accessors (unw_local_addr_space);
891d77787f2SJonathan Schleifer  ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
892d77787f2SJonathan Schleifer                                          fde_base,
893d77787f2SJonathan Schleifer                                          need_unwind_info, 0,
894d77787f2SJonathan Schleifer                                          arg);
895d77787f2SJonathan Schleifer  if (ret < 0)
896d77787f2SJonathan Schleifer    return ret;
897d77787f2SJonathan Schleifer
898d77787f2SJonathan Schleifer  pi->start_ip += ip_offset;
899d77787f2SJonathan Schleifer  pi->end_ip += ip_offset;
900d77787f2SJonathan Schleifer
901d77787f2SJonathan Schleifer  if (ip < pi->start_ip || ip >= pi->end_ip)
902d77787f2SJonathan Schleifer    return -UNW_ENOINFO;
903d77787f2SJonathan Schleifer
904d77787f2SJonathan Schleifer  return 0;
905d77787f2SJonathan Schleifer}
906d77787f2SJonathan Schleifer
907d77787f2SJonathan Schleiferstatic inline const struct table_entry *
908d77787f2SJonathan Schleiferlookup (const struct table_entry *table, size_t table_size, int32_t rel_ip)
909d77787f2SJonathan Schleifer{
910d77787f2SJonathan Schleifer  unsigned long table_len = table_size / sizeof (struct table_entry);
911d77787f2SJonathan Schleifer  const struct table_entry *e = NULL;
912d77787f2SJonathan Schleifer  unsigned long lo, hi, mid;
913d77787f2SJonathan Schleifer
914d77787f2SJonathan Schleifer  /* do a binary search for right entry: */
915d77787f2SJonathan Schleifer  for (lo = 0, hi = table_len; lo < hi;)
916d77787f2SJonathan Schleifer    {
917d77787f2SJonathan Schleifer      mid = (lo + hi) / 2;
918d77787f2SJonathan Schleifer      e = table + mid;
919d77787f2SJonathan Schleifer      Debug (15, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset);
920d77787f2SJonathan Schleifer      if (rel_ip < e->start_ip_offset)
921d77787f2SJonathan Schleifer        hi = mid;
922d77787f2SJonathan Schleifer      else
923d77787f2SJonathan Schleifer        lo = mid + 1;
924d77787f2SJonathan Schleifer    }
925d77787f2SJonathan Schleifer  if (hi <= 0)
926d77787f2SJonathan Schleifer        return NULL;
927d77787f2SJonathan Schleifer  e = table + hi - 1;
928d77787f2SJonathan Schleifer  return e;
929d77787f2SJonathan Schleifer}
930d77787f2SJonathan Schleifer
931d77787f2SJonathan Schleifer#endif /* !UNW_REMOTE_ONLY */
932d77787f2SJonathan Schleifer
933d77787f2SJonathan Schleifer#ifndef UNW_LOCAL_ONLY
934d77787f2SJonathan Schleifer
935d77787f2SJonathan Schleifer/* Lookup an unwind-table entry in remote memory.  Returns 1 if an
936d77787f2SJonathan Schleifer   entry is found, 0 if no entry is found, negative if an error
937d77787f2SJonathan Schleifer   occurred reading remote memory.  */
938d77787f2SJonathan Schleiferstatic int
939d77787f2SJonathan Schleiferremote_lookup (unw_addr_space_t as,
940d77787f2SJonathan Schleifer               unw_word_t table, size_t table_size, int32_t rel_ip,
941d77787f2SJonathan Schleifer               struct table_entry *e, void *arg)
942d77787f2SJonathan Schleifer{
943d77787f2SJonathan Schleifer  unsigned long table_len = table_size / sizeof (struct table_entry);
944d77787f2SJonathan Schleifer  unw_accessors_t *a = unw_get_accessors (as);
945d77787f2SJonathan Schleifer  unsigned long lo, hi, mid;
946d77787f2SJonathan Schleifer  unw_word_t e_addr = 0;
947d77787f2SJonathan Schleifer  int32_t start;
948d77787f2SJonathan Schleifer  int ret;
949d77787f2SJonathan Schleifer
950d77787f2SJonathan Schleifer  /* do a binary search for right entry: */
951d77787f2SJonathan Schleifer  for (lo = 0, hi = table_len; lo < hi;)
952d77787f2SJonathan Schleifer    {
953d77787f2SJonathan Schleifer      mid = (lo + hi) / 2;
954d77787f2SJonathan Schleifer      e_addr = table + mid * sizeof (struct table_entry);
955d77787f2SJonathan Schleifer      if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0)
956d77787f2SJonathan Schleifer        return ret;
957d77787f2SJonathan Schleifer
958d77787f2SJonathan Schleifer      if (rel_ip < start)
959d77787f2SJonathan Schleifer        hi = mid;
960d77787f2SJonathan Schleifer      else
961d77787f2SJonathan Schleifer        lo = mid + 1;
962d77787f2SJonathan Schleifer    }
963d77787f2SJonathan Schleifer  if (hi <= 0)
964d77787f2SJonathan Schleifer    return 0;
965d77787f2SJonathan Schleifer  e_addr = table + (hi - 1) * sizeof (struct table_entry);
966d77787f2SJonathan Schleifer  if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0
967d77787f2SJonathan Schleifer   || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0)
968d77787f2SJonathan Schleifer    return ret;
969d77787f2SJonathan Schleifer  return 1;
970d77787f2SJonathan Schleifer}
971d77787f2SJonathan Schleifer
972d77787f2SJonathan Schleifer#endif /* !UNW_LOCAL_ONLY */
973d77787f2SJonathan Schleifer
974d77787f2SJonathan SchleiferPROTECTED int
975d77787f2SJonathan Schleiferdwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
976d77787f2SJonathan Schleifer                           unw_dyn_info_t *di, unw_proc_info_t *pi,
977d77787f2SJonathan Schleifer                           int need_unwind_info, void *arg)
978d77787f2SJonathan Schleifer{
979d77787f2SJonathan Schleifer  const struct table_entry *e = NULL, *table;
980d77787f2SJonathan Schleifer  unw_word_t segbase = 0, fde_addr;
981d77787f2SJonathan Schleifer  unw_accessors_t *a;
982d77787f2SJonathan Schleifer#ifndef UNW_LOCAL_ONLY
983d77787f2SJonathan Schleifer  struct table_entry ent;
984d77787f2SJonathan Schleifer#endif
985d77787f2SJonathan Schleifer  int ret;
986d77787f2SJonathan Schleifer  unw_word_t debug_frame_base;
987d77787f2SJonathan Schleifer  size_t table_len;
988d77787f2SJonathan Schleifer
989d77787f2SJonathan Schleifer#ifdef UNW_REMOTE_ONLY
990d77787f2SJonathan Schleifer  assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE);
991d77787f2SJonathan Schleifer#else
992d77787f2SJonathan Schleifer  assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
993d77787f2SJonathan Schleifer          || di->format == UNW_INFO_FORMAT_TABLE);
994d77787f2SJonathan Schleifer#endif
995d77787f2SJonathan Schleifer  assert (ip >= di->start_ip && ip < di->end_ip);
996d77787f2SJonathan Schleifer
997d77787f2SJonathan Schleifer  if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
998d77787f2SJonathan Schleifer    {
999d77787f2SJonathan Schleifer      table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
1000d77787f2SJonathan Schleifer      table_len = di->u.rti.table_len * sizeof (unw_word_t);
1001d77787f2SJonathan Schleifer      debug_frame_base = 0;
1002d77787f2SJonathan Schleifer    }
1003d77787f2SJonathan Schleifer  else
1004d77787f2SJonathan Schleifer    {
1005d77787f2SJonathan Schleifer#ifndef UNW_REMOTE_ONLY
1006d77787f2SJonathan Schleifer      struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
1007d77787f2SJonathan Schleifer
1008d77787f2SJonathan Schleifer      /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
1009d77787f2SJonathan Schleifer         space.  Both the index and the unwind tables live in local memory, but
1010d77787f2SJonathan Schleifer         the address space to check for properties like the address size and
1011d77787f2SJonathan Schleifer         endianness is the target one.  */
1012d77787f2SJonathan Schleifer      as = unw_local_addr_space;
1013d77787f2SJonathan Schleifer      table = fdesc->index;
1014d77787f2SJonathan Schleifer      table_len = fdesc->index_size * sizeof (struct table_entry);
1015d77787f2SJonathan Schleifer      debug_frame_base = (uintptr_t) fdesc->debug_frame;
1016d77787f2SJonathan Schleifer#endif
1017d77787f2SJonathan Schleifer    }
1018d77787f2SJonathan Schleifer
1019d77787f2SJonathan Schleifer  a = unw_get_accessors (as);
1020d77787f2SJonathan Schleifer
1021d77787f2SJonathan Schleifer#ifndef UNW_REMOTE_ONLY
1022d77787f2SJonathan Schleifer  if (as == unw_local_addr_space)
1023d77787f2SJonathan Schleifer    {
1024d77787f2SJonathan Schleifer      segbase = di->u.rti.segbase;
1025d77787f2SJonathan Schleifer      e = lookup (table, table_len, ip - segbase);
1026d77787f2SJonathan Schleifer    }
1027d77787f2SJonathan Schleifer  else
1028d77787f2SJonathan Schleifer#endif
1029d77787f2SJonathan Schleifer    {
1030d77787f2SJonathan Schleifer#ifndef UNW_LOCAL_ONLY
1031d77787f2SJonathan Schleifer      segbase = di->u.rti.segbase;
1032d77787f2SJonathan Schleifer      if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
1033d77787f2SJonathan Schleifer                                ip - segbase, &ent, arg)) < 0)
1034d77787f2SJonathan Schleifer        return ret;
1035d77787f2SJonathan Schleifer      if (ret)
1036d77787f2SJonathan Schleifer        e = &ent;
1037d77787f2SJonathan Schleifer      else
1038d77787f2SJonathan Schleifer        e = NULL;       /* no info found */
1039d77787f2SJonathan Schleifer#endif
1040d77787f2SJonathan Schleifer    }
1041d77787f2SJonathan Schleifer  if (!e)
1042d77787f2SJonathan Schleifer    {
1043d77787f2SJonathan Schleifer      Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n",
1044d77787f2SJonathan Schleifer             (long) ip, (long) di->start_ip, (long) di->end_ip);
1045d77787f2SJonathan Schleifer      /* IP is inside this table's range, but there is no explicit
1046d77787f2SJonathan Schleifer         unwind info.  */
1047d77787f2SJonathan Schleifer      return -UNW_ENOINFO;
1048d77787f2SJonathan Schleifer    }
1049d77787f2SJonathan Schleifer  Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
1050d77787f2SJonathan Schleifer         (long) ip, (long) (e->start_ip_offset));
1051d77787f2SJonathan Schleifer  if (debug_frame_base)
1052d77787f2SJonathan Schleifer    fde_addr = e->fde_offset + debug_frame_base;
1053d77787f2SJonathan Schleifer  else
1054d77787f2SJonathan Schleifer    fde_addr = e->fde_offset + segbase;
1055d77787f2SJonathan Schleifer  Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, "
1056d77787f2SJonathan Schleifer            "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
1057d77787f2SJonathan Schleifer            (long) debug_frame_base, (long) fde_addr);
1058d77787f2SJonathan Schleifer  if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
1059d77787f2SJonathan Schleifer                                               debug_frame_base ?
1060d77787f2SJonathan Schleifer                                               debug_frame_base : segbase,
1061d77787f2SJonathan Schleifer                                               need_unwind_info,
1062d77787f2SJonathan Schleifer                                               debug_frame_base != 0, arg)) < 0)
1063d77787f2SJonathan Schleifer    return ret;
1064d77787f2SJonathan Schleifer
1065d77787f2SJonathan Schleifer  /* .debug_frame uses an absolute encoding that does not know about any
1066d77787f2SJonathan Schleifer     shared library relocation.  */
1067d77787f2SJonathan Schleifer  if (di->format == UNW_INFO_FORMAT_TABLE)
1068d77787f2SJonathan Schleifer    {
1069d77787f2SJonathan Schleifer      pi->start_ip += segbase;
1070d77787f2SJonathan Schleifer      pi->end_ip += segbase;
1071d77787f2SJonathan Schleifer      pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
1072d77787f2SJonathan Schleifer    }
1073d77787f2SJonathan Schleifer
1074d77787f2SJonathan Schleifer  if (ip < pi->start_ip || ip >= pi->end_ip)
1075d77787f2SJonathan Schleifer    return -UNW_ENOINFO;
1076d77787f2SJonathan Schleifer
1077d77787f2SJonathan Schleifer  return 0;
1078d77787f2SJonathan Schleifer}
1079d77787f2SJonathan Schleifer
1080d77787f2SJonathan SchleiferHIDDEN void
1081d77787f2SJonathan Schleiferdwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
1082d77787f2SJonathan Schleifer{
1083d77787f2SJonathan Schleifer  return;       /* always a nop */
1084d77787f2SJonathan Schleifer}
1085