1/* libunwind - a platform-independent unwind library
2   Copyright (c) 2001-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#include <assert.h>
27#include <stdlib.h>
28#include <stddef.h>
29
30#include "unwind_i.h"
31
32#ifdef HAVE_IA64INTRIN_H
33# include <ia64intrin.h>
34#endif
35
36extern unw_addr_space_t _ULia64_local_addr_space;
37
38struct ia64_table_entry
39  {
40    uint64_t start_offset;
41    uint64_t end_offset;
42    uint64_t info_offset;
43  };
44
45#ifdef UNW_LOCAL_ONLY
46
47static inline int
48is_local_addr_space (unw_addr_space_t as)
49{
50  return 1;
51}
52
53static inline int
54read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg)
55{
56  *valp = *(unw_word_t *) addr;
57  return 0;
58}
59
60#else /* !UNW_LOCAL_ONLY */
61
62static inline int
63is_local_addr_space (unw_addr_space_t as)
64{
65  return as == unw_local_addr_space;
66}
67
68static inline int
69read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg)
70{
71  unw_accessors_t *a = unw_get_accessors (as);
72
73  return (*a->access_mem) (as, addr, valp, 0, arg);
74}
75
76/* Helper macro for reading an ia64_table_entry from remote memory.  */
77#define remote_read(addr, member)					     \
78	(*a->access_mem) (as, (addr) + offsetof (struct ia64_table_entry,    \
79						 member), &member, 0, arg)
80
81/* Lookup an unwind-table entry in remote memory.  Returns 1 if an
82   entry is found, 0 if no entry is found, negative if an error
83   occurred reading remote memory.  */
84static int
85remote_lookup (unw_addr_space_t as,
86	       unw_word_t table, size_t table_size, unw_word_t rel_ip,
87	       struct ia64_table_entry *e, void *arg)
88{
89  unw_word_t e_addr = 0, start_offset, end_offset, info_offset;
90  unw_accessors_t *a = unw_get_accessors (as);
91  unsigned long lo, hi, mid;
92  int ret;
93
94  /* do a binary search for right entry: */
95  for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;)
96    {
97      mid = (lo + hi) / 2;
98      e_addr = table + mid * sizeof (struct ia64_table_entry);
99      if ((ret = remote_read (e_addr, start_offset)) < 0)
100	return ret;
101
102      if (rel_ip < start_offset)
103	hi = mid;
104      else
105	{
106	  if ((ret = remote_read (e_addr, end_offset)) < 0)
107	    return ret;
108
109	  if (rel_ip >= end_offset)
110	    lo = mid + 1;
111	  else
112	    break;
113	}
114    }
115  if (rel_ip < start_offset || rel_ip >= end_offset)
116    return 0;
117  e->start_offset = start_offset;
118  e->end_offset = end_offset;
119
120  if ((ret = remote_read (e_addr, info_offset)) < 0)
121    return ret;
122  e->info_offset = info_offset;
123  return 1;
124}
125
126HIDDEN void
127tdep_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
128{
129  if (!pi->unwind_info)
130    return;
131
132  if (is_local_addr_space (as))
133    {
134      free (pi->unwind_info);
135      pi->unwind_info = NULL;
136    }
137}
138
139PROTECTED unw_word_t
140_Uia64_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg)
141{
142  unw_word_t hdr_addr, info_addr, hdr, directives, pers, cookie, off;
143  unw_word_t start_offset, end_offset, info_offset, segbase;
144  struct ia64_table_entry *e;
145  size_t table_size;
146  unw_word_t gp = di->gp;
147  int ret;
148
149  switch (di->format)
150    {
151    case UNW_INFO_FORMAT_DYNAMIC:
152    default:
153      return 0;
154
155    case UNW_INFO_FORMAT_TABLE:
156      e = (struct ia64_table_entry *) di->u.ti.table_data;
157      table_size = di->u.ti.table_len * sizeof (di->u.ti.table_data[0]);
158      segbase = di->u.ti.segbase;
159      if (table_size < sizeof (struct ia64_table_entry))
160	return 0;
161      start_offset = e[0].start_offset;
162      end_offset = e[0].end_offset;
163      info_offset = e[0].info_offset;
164      break;
165
166    case UNW_INFO_FORMAT_REMOTE_TABLE:
167      {
168	unw_accessors_t *a = unw_get_accessors (as);
169	unw_word_t e_addr = di->u.rti.table_data;
170
171	table_size = di->u.rti.table_len * sizeof (unw_word_t);
172	segbase = di->u.rti.segbase;
173	if (table_size < sizeof (struct ia64_table_entry))
174	  return 0;
175
176	if (   (ret = remote_read (e_addr, start_offset) < 0)
177	    || (ret = remote_read (e_addr, end_offset) < 0)
178	    || (ret = remote_read (e_addr, info_offset) < 0))
179	  return ret;
180      }
181      break;
182    }
183
184  if (start_offset != end_offset)
185    /* dyn-list entry cover a zero-length "procedure" and should be
186       first entry (note: technically a binary could contain code
187       below the segment base, but this doesn't happen for normal
188       binaries and certainly doesn't happen when libunwind is a
189       separate shared object.  For weird cases, the application may
190       have to provide its own (slower) version of this routine.  */
191    return 0;
192
193  hdr_addr = info_offset + segbase;
194  info_addr = hdr_addr + 8;
195
196  /* read the header word: */
197  if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0)
198    return ret;
199
200  if (IA64_UNW_VER (hdr) != 1
201      || IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
202    /* dyn-list entry must be version 1 and doesn't have ehandler
203       or uhandler */
204    return 0;
205
206  if (IA64_UNW_LENGTH (hdr) != 1)
207    /* dyn-list entry must consist of a single word of NOP directives */
208    return 0;
209
210  if (   ((ret = read_mem (as, info_addr, &directives, arg)) < 0)
211      || ((ret = read_mem (as, info_addr + 0x08, &pers, arg)) < 0)
212      || ((ret = read_mem (as, info_addr + 0x10, &cookie, arg)) < 0)
213      || ((ret = read_mem (as, info_addr + 0x18, &off, arg)) < 0))
214    return 0;
215
216  if (directives != 0 || pers != 0
217      || (!as->big_endian && cookie != 0x7473696c2d6e7964ULL)
218      || ( as->big_endian && cookie != 0x64796e2d6c697374ULL))
219    return 0;
220
221  /* OK, we ran the gauntlet and found it: */
222  return off + gp;
223}
224
225#endif /* !UNW_LOCAL_ONLY */
226
227static inline const struct ia64_table_entry *
228lookup (struct ia64_table_entry *table, size_t table_size, unw_word_t rel_ip)
229{
230  const struct ia64_table_entry *e = 0;
231  unsigned long lo, hi, mid;
232
233  /* do a binary search for right entry: */
234  for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;)
235    {
236      mid = (lo + hi) / 2;
237      e = table + mid;
238      if (rel_ip < e->start_offset)
239	hi = mid;
240      else if (rel_ip >= e->end_offset)
241	lo = mid + 1;
242      else
243	break;
244    }
245  if (rel_ip < e->start_offset || rel_ip >= e->end_offset)
246    return NULL;
247  return e;
248}
249
250PROTECTED int
251unw_search_ia64_unwind_table (unw_addr_space_t as, unw_word_t ip,
252			      unw_dyn_info_t *di, unw_proc_info_t *pi,
253			      int need_unwind_info, void *arg)
254{
255  unw_word_t addr, hdr_addr, info_addr, info_end_addr, hdr, *wp;
256  const struct ia64_table_entry *e = NULL;
257  unw_word_t handler_offset, segbase = 0;
258  int ret, is_local;
259#ifndef UNW_LOCAL_ONLY
260  struct ia64_table_entry ent;
261#endif
262
263  assert ((di->format == UNW_INFO_FORMAT_TABLE
264	   || di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
265	  && (ip >= di->start_ip && ip < di->end_ip));
266
267  pi->flags = 0;
268  pi->unwind_info = 0;
269  pi->handler = 0;
270
271  if (likely (di->format == UNW_INFO_FORMAT_TABLE))
272    {
273      segbase = di->u.ti.segbase;
274      e = lookup ((struct ia64_table_entry *) di->u.ti.table_data,
275		  di->u.ti.table_len * sizeof (unw_word_t),
276		  ip - segbase);
277    }
278#ifndef UNW_LOCAL_ONLY
279  else
280    {
281      segbase = di->u.rti.segbase;
282      if ((ret = remote_lookup (as, di->u.rti.table_data,
283				di->u.rti.table_len * sizeof (unw_word_t),
284				ip - segbase, &ent, arg)) < 0)
285	return ret;
286      if (ret)
287	e = &ent;
288    }
289#endif
290  if (!e)
291    {
292      /* IP is inside this table's range, but there is no explicit
293	 unwind info => use default conventions (i.e., this is NOT an
294	 error).  */
295      memset (pi, 0, sizeof (*pi));
296      pi->start_ip = 0;
297      pi->end_ip = 0;
298      pi->gp = di->gp;
299      pi->lsda = 0;
300      return 0;
301    }
302
303  pi->start_ip = e->start_offset + segbase;
304  pi->end_ip = e->end_offset + segbase;
305
306  hdr_addr = e->info_offset + segbase;
307  info_addr = hdr_addr + 8;
308
309  /* Read the header word.  Note: the actual unwind-info is always
310     assumed to reside in memory, independent of whether di->format is
311     UNW_INFO_FORMAT_TABLE or UNW_INFO_FORMAT_REMOTE_TABLE.  */
312
313  if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0)
314    return ret;
315
316  if (IA64_UNW_VER (hdr) != 1)
317    {
318      Debug (1, "Unknown header version %ld (hdr word=0x%lx @ 0x%lx)\n",
319	     IA64_UNW_VER (hdr), (unsigned long) hdr,
320	     (unsigned long) hdr_addr);
321      return -UNW_EBADVERSION;
322    }
323
324  info_end_addr = info_addr + 8 * IA64_UNW_LENGTH (hdr);
325
326  is_local = is_local_addr_space (as);
327
328  /* If we must have the unwind-info, return it.  Also, if we are in
329     the local address-space, return the unwind-info because it's so
330     cheap to do so and it may come in handy later on.  */
331  if (need_unwind_info || is_local)
332    {
333      pi->unwind_info_size = 8 * IA64_UNW_LENGTH (hdr);
334
335      if (is_local)
336	pi->unwind_info = (void *) (uintptr_t) info_addr;
337      else
338	{
339	  /* Internalize unwind info.  Note: since we're doing this
340	     only for non-local address spaces, there is no
341	     signal-safety issue and it is OK to use malloc()/free().  */
342	  pi->unwind_info = malloc (8 * IA64_UNW_LENGTH (hdr));
343	  if (!pi->unwind_info)
344	    return -UNW_ENOMEM;
345
346	  wp = (unw_word_t *) pi->unwind_info;
347	  for (addr = info_addr; addr < info_end_addr; addr += 8, ++wp)
348	    {
349	      if ((ret = read_mem (as, addr, wp, arg)) < 0)
350		{
351		  free (pi->unwind_info);
352		  return ret;
353		}
354	    }
355	}
356    }
357
358  if (IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
359    {
360      /* read the personality routine address (address is gp-relative): */
361      if ((ret = read_mem (as, info_end_addr, &handler_offset, arg)) < 0)
362	return ret;
363      Debug (4, "handler ptr @ offset=%lx, gp=%lx\n", handler_offset, di->gp);
364      if ((read_mem (as, handler_offset + di->gp, &pi->handler, arg)) < 0)
365	return ret;
366    }
367  pi->lsda = info_end_addr + 8;
368  pi->gp = di->gp;
369  pi->format = di->format;
370  return 0;
371}
372
373#ifndef UNW_REMOTE_ONLY
374
375# if defined(HAVE_DL_ITERATE_PHDR)
376#  include <link.h>
377#  include <stdlib.h>
378
379#  if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
380      || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
381#    error You need GLIBC 2.2.4 or later on IA-64 Linux
382#  endif
383
384#  if defined(HAVE_GETUNWIND)
385     extern unsigned long getunwind (void *buf, size_t len);
386#  else /* HAVE_GETUNWIND */
387#   include <unistd.h>
388#   include <sys/syscall.h>
389#   ifndef __NR_getunwind
390#     define __NR_getunwind	1215
391#   endif
392
393static unsigned long
394getunwind (void *buf, size_t len)
395{
396  return syscall (SYS_getunwind, buf, len);
397}
398
399#  endif /* HAVE_GETUNWIND */
400
401static unw_dyn_info_t kernel_table;
402
403static int
404get_kernel_table (unw_dyn_info_t *di)
405{
406  struct ia64_table_entry *ktab, *etab;
407  size_t size;
408
409  Debug (16, "getting kernel table");
410
411  size = getunwind (NULL, 0);
412  ktab = sos_alloc (size);
413  if (!ktab)
414    {
415      Dprintf (__FILE__".%s: failed to allocate %zu bytes",
416	       __FUNCTION__, size);
417      return -UNW_ENOMEM;
418    }
419  getunwind (ktab, size);
420
421  /* Determine length of kernel's unwind table & relocate its entries.  */
422  for (etab = ktab; etab->start_offset; ++etab)
423    etab->info_offset += (uint64_t) ktab;
424
425  di->format = UNW_INFO_FORMAT_TABLE;
426  di->gp = 0;
427  di->start_ip = ktab[0].start_offset;
428  di->end_ip = etab[-1].end_offset;
429  di->u.ti.name_ptr = (unw_word_t) "<kernel>";
430  di->u.ti.segbase = 0;
431  di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
432  di->u.ti.table_data = (unw_word_t *) ktab;
433
434  Debug (16, "found table `%s': [%lx-%lx) segbase=%lx len=%lu\n",
435	 (char *) di->u.ti.name_ptr, di->start_ip, di->end_ip,
436	 di->u.ti.segbase, di->u.ti.table_len);
437  return 0;
438}
439
440#  ifndef UNW_LOCAL_ONLY
441
442/* This is exported for the benefit of libunwind-ptrace.a.  */
443PROTECTED int
444_Uia64_get_kernel_table (unw_dyn_info_t *di)
445{
446  int ret;
447
448  if (!kernel_table.u.ti.table_data)
449    if ((ret = get_kernel_table (&kernel_table)) < 0)
450      return ret;
451
452  memcpy (di, &kernel_table, sizeof (*di));
453  return 0;
454}
455
456#  endif /* !UNW_LOCAL_ONLY */
457
458static inline unsigned long
459current_gp (void)
460{
461#  if defined(__GNUC__) && !defined(__INTEL_COMPILER)
462      register unsigned long gp __asm__("gp");
463      return gp;
464#  elif HAVE_IA64INTRIN_H
465      return __getReg (_IA64_REG_GP);
466#  else
467#    error Implement me.
468#  endif
469}
470
471static int
472callback (struct dl_phdr_info *info, size_t size, void *ptr)
473{
474  unw_dyn_info_t *di = ptr;
475  const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text;
476  long n;
477  Elf64_Addr load_base, segbase = 0;
478
479  /* Make sure struct dl_phdr_info is at least as big as we need.  */
480  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
481	     + sizeof (info->dlpi_phnum))
482    return -1;
483
484  Debug (16, "checking `%s' (load_base=%lx)\n",
485	 info->dlpi_name, info->dlpi_addr);
486
487  phdr = info->dlpi_phdr;
488  load_base = info->dlpi_addr;
489  p_text = NULL;
490  p_unwind = NULL;
491  p_dynamic = NULL;
492
493  /* See if PC falls into one of the loaded segments.  Find the unwind
494     segment at the same time.  */
495  for (n = info->dlpi_phnum; --n >= 0; phdr++)
496    {
497      if (phdr->p_type == PT_LOAD)
498	{
499	  Elf64_Addr vaddr = phdr->p_vaddr + load_base;
500	  if (di->u.ti.segbase >= vaddr
501	      && di->u.ti.segbase < vaddr + phdr->p_memsz)
502	    p_text = phdr;
503	}
504      else if (phdr->p_type == PT_IA_64_UNWIND)
505	p_unwind = phdr;
506      else if (phdr->p_type == PT_DYNAMIC)
507	p_dynamic = phdr;
508    }
509  if (!p_text || !p_unwind)
510    return 0;
511
512  if (likely (p_unwind->p_vaddr >= p_text->p_vaddr
513	      && p_unwind->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
514    /* normal case: unwind table is inside text segment */
515    segbase = p_text->p_vaddr + load_base;
516  else
517    {
518      /* Special case: unwind table is in some other segment; this
519	 happens for the Linux kernel's gate DSO, for example.  */
520      phdr = info->dlpi_phdr;
521      for (n = info->dlpi_phnum; --n >= 0; phdr++)
522	{
523	  if (phdr->p_type == PT_LOAD && p_unwind->p_vaddr >= phdr->p_vaddr
524	      && p_unwind->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
525	    {
526	      segbase = phdr->p_vaddr + load_base;
527	      break;
528	    }
529	}
530    }
531
532  if (p_dynamic)
533    {
534      /* For dynamicly linked executables and shared libraries,
535	 DT_PLTGOT is the gp value for that object.  */
536      Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
537      for (; dyn->d_tag != DT_NULL; ++dyn)
538	if (dyn->d_tag == DT_PLTGOT)
539	  {
540	    /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it.  */
541	    di->gp = dyn->d_un.d_ptr;
542	    break;
543	  }
544    }
545  else
546    /* Otherwise this is a static executable with no _DYNAMIC.
547       The gp is constant program-wide.  */
548    di->gp = current_gp();
549  di->format = UNW_INFO_FORMAT_TABLE;
550  di->start_ip = p_text->p_vaddr + load_base;
551  di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
552  di->u.ti.name_ptr = (unw_word_t) info->dlpi_name;
553  di->u.ti.table_data = (void *) (p_unwind->p_vaddr + load_base);
554  di->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
555  di->u.ti.segbase = segbase;
556
557  Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, "
558	 "table_data=%p\n", (char *) di->u.ti.name_ptr, di->u.ti.segbase,
559	 di->u.ti.table_len, di->gp, di->u.ti.table_data);
560  return 1;
561}
562
563#  ifdef HAVE_DL_PHDR_REMOVALS_COUNTER
564
565static inline int
566validate_cache (unw_addr_space_t as)
567{
568  /* Note: we don't need to serialize here with respect to
569     dl_iterate_phdr() because if somebody were to remove an object
570     that is required to complete the unwind on whose behalf we're
571     validating the cache here, we'd be hosed anyhow.  What we're
572     guarding against here is the case where library FOO gets mapped,
573     unwind info for FOO gets cached, FOO gets unmapped, BAR gets
574     mapped in the place where FOO was and then we unwind across a
575     function in FOO.  Since no thread can execute in BAR before FOO
576     has been removed, we are guaranteed that
577     dl_phdr_removals_counter() would have been incremented before we
578     get here.  */
579  unsigned long long removals = dl_phdr_removals_counter ();
580
581  if (removals == as->shared_object_removals)
582    return 1;
583
584  as->shared_object_removals = removals;
585  unw_flush_cache (as, 0, 0);
586  return -1;
587}
588
589#  else /* !HAVE_DL_PHDR_REMOVALS_COUNTER */
590
591/* Check whether any phdrs have been removed since we last flushed the
592   cache.  If so we flush the cache and return -1, if not, we do
593   nothing and return 1.  */
594
595static int
596check_callback (struct dl_phdr_info *info, size_t size, void *ptr)
597{
598#   ifdef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS
599  unw_addr_space_t as = ptr;
600
601  if (size <
602      offsetof (struct dl_phdr_info, dlpi_subs) + sizeof (info->dlpi_subs))
603    /* It would be safer to flush the cache here, but that would
604       disable caching for older libc's which would be incompatible
605       with the behavior of older versions of libunwind so we return 1
606       instead and hope nobody runs into stale cache info...  */
607    return 1;
608
609  if (info->dlpi_subs == as->shared_object_removals)
610    return 1;
611
612  as->shared_object_removals = info->dlpi_subs;
613  unw_flush_cache (as, 0, 0);
614  return -1;		/* indicate that there were removals */
615#   else
616  return 1;
617#   endif
618}
619
620static inline int
621validate_cache (unw_addr_space_t as)
622{
623  intrmask_t saved_mask;
624  int ret;
625
626  SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
627  ret = dl_iterate_phdr (check_callback, as);
628  SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
629  return ret;
630}
631
632#  endif /* HAVE_DL_PHDR_REMOVALS_COUNTER */
633
634# elif defined(HAVE_DLMODINFO)
635  /* Support for HP-UX-style dlmodinfo() */
636#  include <dlfcn.h>
637
638static inline int
639validate_cache (unw_addr_space_t as)
640{
641  return 1;
642}
643
644# endif /* !HAVE_DLMODINFO */
645
646HIDDEN int
647tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip,
648		     unw_proc_info_t *pi, int need_unwind_info, void *arg)
649{
650# if defined(HAVE_DL_ITERATE_PHDR)
651  unw_dyn_info_t di, *dip = &di;
652  intrmask_t saved_mask;
653  int ret;
654
655  di.u.ti.segbase = ip;	/* this is cheap... */
656
657  SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
658  ret = dl_iterate_phdr (callback, &di);
659  SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
660
661  if (ret <= 0)
662    {
663      if (!kernel_table.u.ti.table_data)
664	{
665	  if ((ret = get_kernel_table (&kernel_table)) < 0)
666	    return ret;
667	}
668      if (ip < kernel_table.start_ip || ip >= kernel_table.end_ip)
669	return -UNW_ENOINFO;
670      dip = &kernel_table;
671    }
672# elif defined(HAVE_DLMODINFO)
673# define UNWIND_TBL_32BIT	0x8000000000000000
674  struct load_module_desc lmd;
675  unw_dyn_info_t di, *dip = &di;
676  struct unwind_header
677    {
678      uint64_t header_version;
679      uint64_t start_offset;
680      uint64_t end_offset;
681    }
682  *uhdr;
683
684  if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0))
685    return -UNW_ENOINFO;
686
687  di.format = UNW_INFO_FORMAT_TABLE;
688  di.start_ip = lmd.text_base;
689  di.end_ip = lmd.text_base + lmd.text_size;
690  di.gp = lmd.linkage_ptr;
691  di.u.ti.name_ptr = 0;	/* no obvious table-name available */
692  di.u.ti.segbase = lmd.text_base;
693
694  uhdr = (struct unwind_header *) lmd.unwind_base;
695
696  if ((uhdr->header_version & ~UNWIND_TBL_32BIT) != 1
697      && (uhdr->header_version & ~UNWIND_TBL_32BIT) != 2)
698    {
699      Debug (1, "encountered unknown unwind header version %ld\n",
700 	     (long) (uhdr->header_version & ~UNWIND_TBL_32BIT));
701      return -UNW_EBADVERSION;
702    }
703  if (uhdr->header_version & UNWIND_TBL_32BIT)
704    {
705      Debug (1, "32-bit unwind tables are not supported yet\n");
706      return -UNW_EINVAL;
707    }
708
709  di.u.ti.table_data = (unw_word_t *) (di.u.ti.segbase + uhdr->start_offset);
710  di.u.ti.table_len = ((uhdr->end_offset - uhdr->start_offset)
711		       / sizeof (unw_word_t));
712
713  Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, "
714 	 "table_data=%p\n", (char *) di.u.ti.name_ptr, di.u.ti.segbase,
715 	 di.u.ti.table_len, di.gp, di.u.ti.table_data);
716# endif
717
718  /* now search the table: */
719  return tdep_search_unwind_table (as, ip, dip, pi, need_unwind_info, arg);
720}
721
722/* Returns 1 if the cache is up-to-date or -1 if the cache contained
723   stale data and had to be flushed.  */
724
725HIDDEN int
726ia64_local_validate_cache (unw_addr_space_t as, void *arg)
727{
728  return validate_cache (as);
729}
730
731#endif /* !UNW_REMOTE_ONLY */
732