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