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