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