Gtables.c revision 2142c20307343000510c3cd6d3dc87de0a21ea1a
1/* libunwind - a platform-independent unwind library
2   Copyright (c) 2001-2004 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;
259
260  assert ((di->format == UNW_INFO_FORMAT_TABLE
261	   || di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
262	  && (ip >= di->start_ip && ip < di->end_ip));
263
264  pi->flags = 0;
265  pi->unwind_info = 0;
266  pi->handler = 0;
267
268  if (likely (di->format == UNW_INFO_FORMAT_TABLE))
269    {
270      segbase = di->u.ti.segbase;
271      e = lookup ((struct ia64_table_entry *) di->u.ti.table_data,
272		  di->u.ti.table_len * sizeof (unw_word_t),
273		  ip - segbase);
274    }
275#ifndef UNW_LOCAL_ONLY
276  else
277    {
278      struct ia64_table_entry ent;
279
280      segbase = di->u.rti.segbase;
281      if ((ret = remote_lookup (as, di->u.rti.table_data,
282				di->u.rti.table_len * sizeof (unw_word_t),
283				ip - segbase, &ent, arg)) < 0)
284	return ret;
285      if (ret)
286	e = &ent;
287    }
288#endif
289  if (!e)
290    {
291      /* IP is inside this table's range, but there is no explicit
292	 unwind info => use default conventions (i.e., this is NOT an
293	 error).  */
294      memset (pi, 0, sizeof (*pi));
295      pi->start_ip = 0;
296      pi->end_ip = 0;
297      pi->gp = di->gp;
298      pi->lsda = 0;
299      return 0;
300    }
301
302  pi->start_ip = e->start_offset + segbase;
303  pi->end_ip = e->end_offset + segbase;
304
305  hdr_addr = e->info_offset + segbase;
306  info_addr = hdr_addr + 8;
307
308  /* read the header word: */
309  if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0)
310    return ret;
311
312  if (IA64_UNW_VER (hdr) != 1)
313    return -UNW_EBADVERSION;
314
315  info_end_addr = info_addr + 8 * IA64_UNW_LENGTH (hdr);
316
317  if (need_unwind_info)
318    {
319      pi->unwind_info_size = 8 * IA64_UNW_LENGTH (hdr);
320
321      if (is_local_addr_space (as))
322	pi->unwind_info = (void *) (uintptr_t) info_addr;
323      else
324	{
325	  /* Internalize unwind info.  Note: since we're doing this
326	     only for non-local address spaces, there is no
327	     signal-safety issue and it is OK to use malloc()/free().  */
328	  pi->unwind_info = malloc (8 * IA64_UNW_LENGTH (hdr));
329	  if (!pi->unwind_info)
330	    return -UNW_ENOMEM;
331
332	  wp = (unw_word_t *) pi->unwind_info;
333	  for (addr = info_addr; addr < info_end_addr; addr += 8, ++wp)
334	    {
335	      if ((ret = read_mem (as, addr, wp, arg)) < 0)
336		{
337		  free (pi->unwind_info);
338		  return ret;
339		}
340	    }
341	}
342    }
343
344  if (IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
345    {
346      /* read the personality routine address (address is gp-relative): */
347      if ((ret = read_mem (as, info_end_addr, &handler_offset, arg)) < 0)
348	return ret;
349      Debug (4, "handler ptr @ offset=%lx, gp=%lx\n", handler_offset, di->gp);
350      if ((read_mem (as, handler_offset + di->gp, &pi->handler, arg)) < 0)
351	return ret;
352    }
353  pi->lsda = info_end_addr + 8;
354  pi->gp = di->gp;
355  pi->format = di->format;
356  return 0;
357}
358
359#ifndef UNW_REMOTE_ONLY
360
361# if defined(HAVE_DL_ITERATE_PHDR)
362#  include <link.h>
363#  include <stdlib.h>
364
365#  if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
366      || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
367#    error You need GLIBC 2.2.4 or later on IA-64 Linux
368#  endif
369
370#  if defined(HAVE_GETUNWIND)
371     extern unsigned long getunwind (void *buf, size_t len);
372#  else /* HAVE_GETUNWIND */
373#   include <unistd.h>
374#   include <sys/syscall.h>
375#   ifndef __NR_getunwind
376#     define __NR_getunwind	1215
377#   endif
378
379static unsigned long
380getunwind (void *buf, size_t len)
381{
382  return syscall (SYS_getunwind, buf, len);
383}
384
385#  endif /* HAVE_GETUNWIND */
386
387static unw_dyn_info_t kernel_table;
388
389static int
390get_kernel_table (unw_dyn_info_t *di)
391{
392  struct ia64_table_entry *ktab, *etab;
393  size_t size;
394
395  Debug (16, "getting kernel table");
396
397  size = getunwind (NULL, 0);
398  ktab = sos_alloc (size);
399  if (!ktab)
400    {
401      dprintf (__FILE__".%s: failed to allocate %zu bytes",
402	       __FUNCTION__, size);
403      return -UNW_ENOMEM;
404    }
405  getunwind (ktab, size);
406
407  /* Determine length of kernel's unwind table & relocate its entries.  */
408  for (etab = ktab; etab->start_offset; ++etab)
409    etab->info_offset += (uint64_t) ktab;
410
411  di->format = UNW_INFO_FORMAT_TABLE;
412  di->gp = 0;
413  di->start_ip = ktab[0].start_offset;
414  di->end_ip = etab[-1].end_offset;
415  di->u.ti.name_ptr = (unw_word_t) "<kernel>";
416  di->u.ti.segbase = 0;
417  di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
418  di->u.ti.table_data = (unw_word_t *) ktab;
419
420  Debug (16, "found table `%s': [%lx-%lx) segbase=%lx len=%lu\n",
421	 (char *) di->u.ti.name_ptr, di->start_ip, di->end_ip,
422	 di->u.ti.segbase, di->u.ti.table_len);
423  return 0;
424}
425
426#  ifndef UNW_LOCAL_ONLY
427
428/* This is exported for the benefit of libunwind-ptrace.a.  */
429PROTECTED int
430_Uia64_get_kernel_table (unw_dyn_info_t *di)
431{
432  int ret;
433
434  if (!kernel_table.u.ti.table_data)
435    if ((ret = get_kernel_table (&kernel_table)) < 0)
436      return ret;
437
438  memcpy (di, &kernel_table, sizeof (*di));
439  return 0;
440}
441
442#  endif /* !UNW_LOCAL_ONLY */
443
444static inline unsigned long
445current_gp (void)
446{
447#  if defined(__GNUC__) && !defined(__INTEL_COMPILER)
448      register unsigned long gp __asm__("gp");
449      return gp;
450#  elif HAVE_IA64INTRIN_H
451      return __getReg (_IA64_REG_GP);
452#  else
453#    error Implement me.
454#  endif
455}
456
457static int
458callback (struct dl_phdr_info *info, size_t size, void *ptr)
459{
460  unw_dyn_info_t *di = ptr;
461  const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text;
462  long n;
463  Elf64_Addr load_base, segbase = 0;
464
465  /* Make sure struct dl_phdr_info is at least as big as we need.  */
466  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
467	     + sizeof (info->dlpi_phnum))
468    return -1;
469
470  Debug (16, "checking `%s' (load_base=%lx)\n",
471	 info->dlpi_name, info->dlpi_addr);
472
473  phdr = info->dlpi_phdr;
474  load_base = info->dlpi_addr;
475  p_text = NULL;
476  p_unwind = NULL;
477  p_dynamic = NULL;
478
479  /* See if PC falls into one of the loaded segments.  Find the unwind
480     segment at the same time.  */
481  for (n = info->dlpi_phnum; --n >= 0; phdr++)
482    {
483      if (phdr->p_type == PT_LOAD)
484	{
485	  Elf64_Addr vaddr = phdr->p_vaddr + load_base;
486	  if (di->u.ti.segbase >= vaddr
487	      && di->u.ti.segbase < vaddr + phdr->p_memsz)
488	    p_text = phdr;
489	}
490      else if (phdr->p_type == PT_IA_64_UNWIND)
491	p_unwind = phdr;
492      else if (phdr->p_type == PT_DYNAMIC)
493	p_dynamic = phdr;
494    }
495  if (!p_text || !p_unwind)
496    return 0;
497
498  if (likely (p_unwind->p_vaddr >= p_text->p_vaddr
499	      && p_unwind->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
500    /* normal case: unwind table is inside text segment */
501    segbase = p_text->p_vaddr + load_base;
502  else
503    {
504      /* Special case: unwind table is in some other segment; this
505	 happens for the Linux kernel's gate DSO, for example.  */
506      phdr = info->dlpi_phdr;
507      for (n = info->dlpi_phnum; --n >= 0; phdr++)
508	{
509	  if (phdr->p_type == PT_LOAD && p_unwind->p_vaddr >= phdr->p_vaddr
510	      && p_unwind->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
511	    {
512	      segbase = phdr->p_vaddr + load_base;
513	      break;
514	    }
515	}
516    }
517
518  if (p_dynamic)
519    {
520      /* For dynamicly linked executables and shared libraries,
521	 DT_PLTGOT is the gp value for that object.  */
522      Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
523      for (; dyn->d_tag != DT_NULL; ++dyn)
524	if (dyn->d_tag == DT_PLTGOT)
525	  {
526	    /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it.  */
527	    di->gp = dyn->d_un.d_ptr;
528	    break;
529	  }
530    }
531  else
532    /* Otherwise this is a static executable with no _DYNAMIC.
533       The gp is constant program-wide.  */
534    di->gp = current_gp();
535  di->format = UNW_INFO_FORMAT_TABLE;
536  di->start_ip = p_text->p_vaddr + load_base;
537  di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
538  di->u.ti.name_ptr = (unw_word_t) info->dlpi_name;
539  di->u.ti.table_data = (void *) (p_unwind->p_vaddr + load_base);
540  di->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
541  di->u.ti.segbase = segbase;
542
543  Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, "
544	 "table_data=%p\n", (char *) di->u.ti.name_ptr, di->u.ti.segbase,
545	 di->u.ti.table_len, di->gp, di->u.ti.table_data);
546  return 1;
547}
548
549#  ifdef HAVE_DL_PHDR_REMOVALS_COUNTER
550
551static inline int
552validate_cache (unw_addr_space_t as)
553{
554  /* Note: we don't need to serialize here with respect to
555     dl_iterate_phdr() because if somebody were to remove an object
556     that is required to complete the unwind on whose behalf we're
557     validating the cache here, we'd be hosed anyhow.  What we're
558     guarding against here is the case where library FOO gets mapped,
559     unwind info for FOO gets cached, FOO gets unmapped, BAR gets
560     mapped in the place where FOO was and then we unwind across a
561     function in FOO.  Since no thread can execute in BAR before FOO
562     has been removed, we are guaranteed that
563     dl_phdr_removals_counter() would have been incremented before we
564     get here.  */
565  unsigned long long removals = dl_phdr_removals_counter ();
566
567  if (removals == as->shared_object_removals)
568    return 1;
569
570  as->shared_object_removals = removals;
571  unw_flush_cache (as, 0, 0);
572  return -1;
573}
574
575#  else /* !HAVE_DL_PHDR_REMOVALS_COUNTER */
576
577/* Check whether any phdrs have been removed since we last flushed the
578   cache.  If so we flush the cache and return -1, if not, we do
579   nothing and return 1.  */
580
581static int
582check_callback (struct dl_phdr_info *info, size_t size, void *ptr)
583{
584#   ifdef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS
585  unw_addr_space_t as = ptr;
586
587  if (size <
588      offsetof (struct dl_phdr_info, dlpi_subs) + sizeof (info->dlpi_subs))
589    /* It would be safer to flush the cache here, but that would
590       disable caching for older libc's which would be incompatible
591       with the behavior of older versions of libunwind so we return 1
592       instead and hope nobody runs into stale cache info...  */
593    return 1;
594
595  if (info->dlpi_subs == as->shared_object_removals)
596    return 1;
597
598  as->shared_object_removals = info->dlpi_subs;
599  unw_flush_cache (as, 0, 0);
600  return -1;		/* indicate that there were removals */
601#   else
602  return 1;
603#   endif
604}
605
606static inline int
607validate_cache (unw_addr_space_t as)
608{
609  sigset_t saved_sigmask;
610  int ret;
611
612  sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask);
613  ret = dl_iterate_phdr (check_callback, as);
614  sigprocmask (SIG_SETMASK, &saved_sigmask, NULL);
615  return ret;
616}
617
618#  endif /* HAVE_DL_PHDR_REMOVALS_COUNTER */
619
620# elif defined(HAVE_DLMODINFO)
621  /* Support for HP-UX-style dlmodinfo() */
622#  include <dlfcn.h>
623
624static inline int
625validate_cache (unw_addr_space_t as)
626{
627  return 1;
628}
629
630# endif /* !HAVE_DLMODINFO */
631
632HIDDEN int
633tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip,
634		     unw_proc_info_t *pi, int need_unwind_info, void *arg)
635{
636# if defined(HAVE_DL_ITERATE_PHDR)
637  unw_dyn_info_t di, *dip = &di;
638  sigset_t saved_sigmask;
639  int ret;
640
641  di.u.ti.segbase = ip;	/* this is cheap... */
642
643  sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask);
644  ret = dl_iterate_phdr (callback, &di);
645  sigprocmask (SIG_SETMASK, &saved_sigmask, NULL);
646
647  if (ret <= 0)
648    {
649      if (!kernel_table.u.ti.table_data)
650	{
651	  if ((ret = get_kernel_table (&kernel_table)) < 0)
652	    return ret;
653	}
654      if (ip < kernel_table.start_ip || ip >= kernel_table.end_ip)
655	return -UNW_ENOINFO;
656      dip = &kernel_table;
657    }
658# elif defined(HAVE_DLMODINFO)
659# define UNWIND_TBL_32BIT	0x8000000000000000
660  struct load_module_desc lmd;
661  unw_dyn_info_t di, *dip = &di;
662  struct unwind_header
663    {
664      uint64_t header_version;
665      uint64_t start_offset;
666      uint64_t end_offset;
667    }
668  *uhdr;
669
670  if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0))
671    return -UNW_ENOINFO;
672
673  di.format = UNW_INFO_FORMAT_TABLE;
674  di.start_ip = lmd.text_base;
675  di.end_ip = lmd.text_base + lmd.text_size;
676  di.gp = lmd.linkage_ptr;
677  di.u.ti.name_ptr = 0;	/* no obvious table-name available */
678  di.u.ti.segbase = lmd.text_base;
679
680  uhdr = (struct unwind_header *) lmd.unwind_base;
681
682  if ((uhdr->header_version & ~UNWIND_TBL_32BIT) != 1
683      && (uhdr->header_version & ~UNWIND_TBL_32BIT) != 2)
684    {
685      Debug (1, "encountered unknown unwind header version %ld\n",
686 	     (long) (uhdr->header_version & ~UNWIND_TBL_32BIT));
687      return -UNW_EBADVERSION;
688    }
689  if (uhdr->header_version & UNWIND_TBL_32BIT)
690    {
691      Debug (1, "32-bit unwind tables are not supported yet\n");
692      return -UNW_EINVAL;
693    }
694
695  di.u.ti.table_data = (unw_word_t *) (di.u.ti.segbase + uhdr->start_offset);
696  di.u.ti.table_len = ((uhdr->end_offset - uhdr->start_offset)
697		       / sizeof (unw_word_t));
698
699  Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, "
700 	 "table_data=%p\n", (char *) di.u.ti.name_ptr, di.u.ti.segbase,
701 	 di.u.ti.table_len, di.gp, di.u.ti.table_data);
702# endif
703
704  /* now search the table: */
705  return tdep_search_unwind_table (as, ip, dip, pi, need_unwind_info, arg);
706}
707
708/* Returns 1 if the cache is up-to-date or -1 if the cache contained
709   stale data and had to be flushed.  */
710
711HIDDEN int
712ia64_local_validate_cache (unw_addr_space_t as, void *arg)
713{
714  return validate_cache (as);
715}
716
717#endif /* !UNW_REMOTE_ONLY */
718