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