Gfind_proc_info-lsb.c revision b56375e76a0e23b6e464d994bc6a790e086b91db
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 225/* Locate the binary which originated the contents of address ADDR. Return 226 the name of the binary in *name (space is allocated by the caller) 227 Returns 0 if a binary is successfully found, or 1 if an error occurs. */ 228 229static int 230find_binary_for_address (unw_word_t ip, char *name, size_t name_size) 231{ 232#ifdef __linux 233 struct map_iterator mi; 234 int found = 0; 235 int pid = getpid (); 236 unsigned long segbase, mapoff, hi; 237 238 maps_init (&mi, pid); 239 while (maps_next (&mi, &segbase, &hi, &mapoff)) 240 if (ip >= segbase && ip < hi) 241 { 242 size_t len = strlen (mi.path); 243 244 if (len + 1 <= name_size) 245 { 246 memcpy (name, mi.path, len + 1); 247 found = 1; 248 } 249 break; 250 } 251 maps_close (&mi); 252 return !found; 253#endif 254 255 return 1; 256} 257 258/* Locate and/or try to load a debug_frame section for address ADDR. Return 259 pointer to debug frame descriptor, or zero if not found. */ 260 261static struct unw_debug_frame_list * 262locate_debug_info (unw_addr_space_t as, struct dl_phdr_info *info, 263 unw_word_t addr, const char *dlname) 264{ 265 struct unw_debug_frame_list *w, *fdesc = 0; 266 char path[PATH_MAX]; 267 char *name = path; 268 int err; 269 uint64_t start = 0, end = 0; 270 char *buf; 271 size_t bufsize; 272 unsigned int i; 273 274 /* First, see if we loaded this frame already. */ 275 276 for (w = as->debug_frames; w; w = w->next) 277 { 278 Debug (4, "checking %p: %x-%x\n", w, (int)w->start, (int)w->end); 279 if (addr >= w->start && addr < w->end) 280 return w; 281 } 282 283 /* If the object name we receive is blank, there's still a chance of locating 284 the file by parsing /proc/self/maps. */ 285 286 if (strcmp (dlname, "") == 0) 287 { 288 err = find_binary_for_address (addr, name, sizeof(path)); 289 if (err) 290 { 291 Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n", 292 (uint64_t) addr); 293 return 0; 294 } 295 } 296 else 297 name = (char*) dlname; 298 299 /* Find the start/end of the described region by parsing the 300 dl_phdr_info structure. */ 301 302 start = info->dlpi_addr + info->dlpi_phdr[0].p_vaddr; 303 end = start; 304 305 for (i = 0; i < info->dlpi_phnum; i++) 306 { 307 Elf_W (Addr) hdrbase = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; 308 Elf_W (Addr) hdrlimit = hdrbase + info->dlpi_phdr[i].p_memsz; 309 310 if (info->dlpi_phdr[i].p_type != PT_LOAD) 311 continue; 312 313 if (hdrbase < start) 314 start = hdrbase; 315 if (hdrlimit > end) 316 end = hdrlimit; 317 } 318 319 Debug (4, "calculated bounds of %x-%x for '%s'\n", (int)start, (int)end, 320 name); 321 322 err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space); 323 324 if (!err) 325 { 326 fdesc = malloc (sizeof (struct unw_debug_frame_list)); 327 328 fdesc->start = start; 329 fdesc->end = end; 330 fdesc->debug_frame = buf; 331 fdesc->debug_frame_size = bufsize; 332 fdesc->index = NULL; 333 fdesc->next = as->debug_frames; 334 335 as->debug_frames = fdesc; 336 } 337 338 return fdesc; 339} 340 341struct debug_frame_tab 342 { 343 struct table_entry *tab; 344 uint32_t length; 345 uint32_t size; 346 }; 347 348static struct debug_frame_tab * 349debug_frame_tab_new (unsigned int base_size) 350{ 351 struct debug_frame_tab *tab = malloc (sizeof (struct debug_frame_tab)); 352 353 tab->tab = calloc (base_size, sizeof (struct table_entry)); 354 tab->length = 0; 355 tab->size = base_size; 356 357 return tab; 358} 359 360static void 361debug_frame_tab_append (struct debug_frame_tab *tab, 362 unw_word_t fde_offset, unw_word_t start_ip) 363{ 364 unsigned int length = tab->length; 365 366 if (length == tab->size) 367 { 368 tab->size *= 2; 369 tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size); 370 } 371 372 tab->tab[length].fde_offset = fde_offset; 373 tab->tab[length].start_ip_offset = start_ip; 374 375 tab->length = length + 1; 376} 377 378static void 379debug_frame_tab_shrink (struct debug_frame_tab *tab) 380{ 381 if (tab->size > tab->length) 382 { 383 tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length); 384 tab->size = tab->length; 385 } 386} 387 388static int 389debug_frame_tab_compare (const void *a, const void *b) 390{ 391 const struct table_entry *fa = a, *fb = b; 392 393 if (fa->start_ip_offset > fb->start_ip_offset) 394 return 1; 395 else if (fa->start_ip_offset < fb->start_ip_offset) 396 return -1; 397 else 398 return 0; 399} 400 401#endif /* CONFIG_DEBUG_FRAME */ 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#ifdef CONFIG_DEBUG_FRAME 579 580 Debug (15, "Trying to find .debug_frame\n"); 581 di = &cb_data->di_debug; 582 fdesc = locate_debug_info (unw_local_addr_space, info, ip, info->dlpi_name); 583 584 if (!fdesc) 585 { 586 Debug (15, "couldn't load .debug_frame\n"); 587 return found; 588 } 589 else 590 { 591 char *buf; 592 size_t bufsize; 593 unw_word_t item_start, item_end = 0; 594 uint32_t u32val = 0; 595 uint64_t cie_id = 0; 596 struct debug_frame_tab *tab; 597 598 Debug (15, "loaded .debug_frame\n"); 599 600 buf = fdesc->debug_frame; 601 bufsize = fdesc->debug_frame_size; 602 603 if (bufsize == 0) 604 { 605 Debug (15, "zero-length .debug_frame\n"); 606 return found; 607 } 608 609 /* Now create a binary-search table, if it does not already exist. */ 610 if (!fdesc->index) 611 { 612 addr = (unw_word_t) (uintptr_t) buf; 613 614 a = unw_get_accessors (unw_local_addr_space); 615 616 /* Find all FDE entries in debug_frame, and make into a sorted 617 index. */ 618 619 tab = debug_frame_tab_new (16); 620 621 while (addr < (unw_word_t) (uintptr_t) (buf + bufsize)) 622 { 623 uint64_t id_for_cie; 624 item_start = addr; 625 626 dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL); 627 628 if (u32val == 0) 629 break; 630 else if (u32val != 0xffffffff) 631 { 632 uint32_t cie_id32 = 0; 633 item_end = addr + u32val; 634 dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32, 635 NULL); 636 cie_id = cie_id32; 637 id_for_cie = 0xffffffff; 638 } 639 else 640 { 641 uint64_t u64val = 0; 642 /* Extended length. */ 643 dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL); 644 item_end = addr + u64val; 645 646 dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL); 647 id_for_cie = 0xffffffffffffffffull; 648 } 649 650 /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/ 651 652 if (cie_id == id_for_cie) 653 ; 654 /*Debug (1, "Found CIE at %.8x.\n", item_start);*/ 655 else 656 { 657 unw_word_t fde_addr = item_start; 658 unw_proc_info_t this_pi; 659 int err; 660 661 /*Debug (1, "Found FDE at %.8x\n", item_start);*/ 662 663 err = dwarf_extract_proc_info_from_fde (unw_local_addr_space, 664 a, &fde_addr, 665 &this_pi, 0, 666 (uintptr_t) buf, 667 NULL); 668 if (err == 0) 669 { 670 Debug (15, "start_ip = %x, end_ip = %x\n", 671 (int) this_pi.start_ip, (int) this_pi.end_ip); 672 debug_frame_tab_append (tab, 673 item_start - (unw_word_t) (uintptr_t) buf, 674 this_pi.start_ip); 675 } 676 /*else 677 Debug (1, "FDE parse failed\n");*/ 678 } 679 680 addr = item_end; 681 } 682 683 debug_frame_tab_shrink (tab); 684 qsort (tab->tab, tab->length, sizeof (struct table_entry), 685 debug_frame_tab_compare); 686 /* for (i = 0; i < tab->length; i++) 687 { 688 fprintf (stderr, "ip %x, fde offset %x\n", 689 (int) tab->tab[i].start_ip_offset, 690 (int) tab->tab[i].fde_offset); 691 }*/ 692 fdesc->index = tab->tab; 693 fdesc->index_size = tab->length; 694 free (tab); 695 } 696 697 di->format = UNW_INFO_FORMAT_TABLE; 698 di->start_ip = fdesc->start; 699 di->end_ip = fdesc->end; 700 di->u.ti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name; 701 di->u.ti.table_data = (unw_word_t *) fdesc; 702 di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t); 703 di->u.ti.segbase = (unw_word_t) (uintptr_t) info->dlpi_addr; 704 705 found = 1; 706 Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, " 707 "gp=0x%lx, table_data=0x%lx\n", 708 (char *) (uintptr_t) di->u.ti.name_ptr, 709 (long) di->u.ti.segbase, (long) di->u.ti.table_len, 710 (long) di->gp, (long) di->u.ti.table_data); 711 } 712#endif /* CONFIG_DEBUG_FRAME */ 713 714 return found; 715} 716 717HIDDEN int 718dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip, 719 unw_proc_info_t *pi, int need_unwind_info, void *arg) 720{ 721 struct callback_data cb_data; 722 intrmask_t saved_mask; 723 int ret; 724 725 Debug (14, "looking for IP=0x%lx\n", (long) ip); 726 727 memset (&cb_data, 0, sizeof (cb_data)); 728 cb_data.ip = ip; 729 cb_data.pi = pi; 730 cb_data.need_unwind_info = need_unwind_info; 731 cb_data.di.format = -1; 732 cb_data.di_debug.format = -1; 733 734 SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask); 735 ret = dl_iterate_phdr (callback, &cb_data); 736 SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL); 737 738 if (ret <= 0) 739 { 740 Debug (14, "IP=0x%lx not found\n", (long) ip); 741 return -UNW_ENOINFO; 742 } 743 744 if (cb_data.single_fde) 745 /* already got the result in *pi */ 746 return 0; 747 748 /* search the table: */ 749 if (cb_data.di.format != -1) 750 ret = dwarf_search_unwind_table (as, ip, &cb_data.di, 751 pi, need_unwind_info, arg); 752 else 753 ret = -UNW_ENOINFO; 754 755 if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1) 756 ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi, 757 need_unwind_info, arg); 758 return ret; 759} 760 761static inline const struct table_entry * 762lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip) 763{ 764 unsigned long table_len = table_size / sizeof (struct table_entry); 765 const struct table_entry *e = 0; 766 unsigned long lo, hi, mid; 767 768 /* do a binary search for right entry: */ 769 for (lo = 0, hi = table_len; lo < hi;) 770 { 771 mid = (lo + hi) / 2; 772 e = table + mid; 773 Debug (1, "e->start_ip_offset = %x\n", (int) e->start_ip_offset); 774 if (rel_ip < e->start_ip_offset) 775 hi = mid; 776 else 777 lo = mid + 1; 778 } 779 if (hi <= 0) 780 return NULL; 781 e = table + hi - 1; 782 return e; 783} 784 785#endif /* !UNW_REMOTE_ONLY */ 786 787#ifndef UNW_LOCAL_ONLY 788 789/* Lookup an unwind-table entry in remote memory. Returns 1 if an 790 entry is found, 0 if no entry is found, negative if an error 791 occurred reading remote memory. */ 792static int 793remote_lookup (unw_addr_space_t as, 794 unw_word_t table, size_t table_size, int32_t rel_ip, 795 struct table_entry *e, void *arg) 796{ 797 unsigned long table_len = table_size / sizeof (struct table_entry); 798 unw_accessors_t *a = unw_get_accessors (as); 799 unsigned long lo, hi, mid; 800 unw_word_t e_addr = 0; 801 int32_t start; 802 int ret; 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_addr = table + mid * sizeof (struct table_entry); 809 if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0) 810 return ret; 811 812 if (rel_ip < start) 813 hi = mid; 814 else 815 lo = mid + 1; 816 } 817 if (hi <= 0) 818 return 0; 819 e_addr = table + (hi - 1) * sizeof (struct table_entry); 820 if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0 821 || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0) 822 return ret; 823 return 1; 824} 825 826#endif /* !UNW_LOCAL_ONLY */ 827 828PROTECTED int 829dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, 830 unw_dyn_info_t *di, unw_proc_info_t *pi, 831 int need_unwind_info, void *arg) 832{ 833 const struct table_entry *e = NULL, *table; 834 unw_word_t segbase = 0, fde_addr; 835 unw_accessors_t *a; 836#ifndef UNW_LOCAL_ONLY 837 struct table_entry ent; 838#endif 839 int ret; 840 unw_word_t debug_frame_base; 841 size_t table_len; 842 843#ifdef UNW_REMOTE_ONLY 844 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE); 845#else 846 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE 847 || di->format == UNW_INFO_FORMAT_TABLE); 848#endif 849 assert (ip >= di->start_ip && ip < di->end_ip); 850 851 if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE) 852 { 853 table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data; 854 table_len = di->u.rti.table_len * sizeof (unw_word_t); 855 debug_frame_base = 0; 856 } 857 else 858 { 859#ifndef UNW_REMOTE_ONLY 860 struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data; 861 862 /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is currently only 863 supported for the local address space. Both the index and 864 the unwind tables live in local memory, but the address space 865 to check for properties like the address size and endianness 866 is the target one. When the ptrace code adds support for 867 .debug_frame something will have to change. */ 868 assert (as == unw_local_addr_space); 869 table = fdesc->index; 870 table_len = fdesc->index_size * sizeof (struct table_entry); 871 debug_frame_base = (uintptr_t) fdesc->debug_frame; 872#endif 873 } 874 875 a = unw_get_accessors (as); 876 877#ifndef UNW_REMOTE_ONLY 878 if (as == unw_local_addr_space) 879 { 880 segbase = di->u.rti.segbase; 881 e = lookup (table, table_len, ip - segbase); 882 } 883 else 884#endif 885 { 886#ifndef UNW_LOCAL_ONLY 887 segbase = di->u.rti.segbase; 888 if ((ret = remote_lookup (as, (uintptr_t) table, table_len, 889 ip - segbase, &ent, arg)) < 0) 890 return ret; 891 if (ret) 892 e = &ent; 893 else 894 e = NULL; /* no info found */ 895#endif 896 } 897 if (!e) 898 { 899 Debug (1, "IP %x inside range %x-%x, but no explicit unwind info found\n", 900 (int) ip, (int) di->start_ip, (int) di->end_ip); 901 /* IP is inside this table's range, but there is no explicit 902 unwind info. */ 903 return -UNW_ENOINFO; 904 } 905 Debug (15, "ip=0x%lx, start_ip=0x%lx\n", 906 (long) ip, (long) (e->start_ip_offset)); 907 if (debug_frame_base) 908 fde_addr = e->fde_offset + debug_frame_base; 909 else 910 fde_addr = e->fde_offset + segbase; 911 Debug (1, "e->fde_offset = %x, segbase = %x, debug_frame_base = %x, " 912 "fde_addr = %x\n", (int) e->fde_offset, (int) segbase, 913 (int) debug_frame_base, (int) fde_addr); 914 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi, 915 need_unwind_info, 916 debug_frame_base, arg)) < 0) 917 return ret; 918 919 /* .debug_frame uses an absolute encoding that does not know about any 920 shared library relocation. */ 921 if (di->format == UNW_INFO_FORMAT_TABLE) 922 { 923 pi->start_ip += segbase; 924 pi->end_ip += segbase; 925 } 926 927 if (ip < pi->start_ip || ip >= pi->end_ip) 928 return -UNW_ENOINFO; 929 930 return 0; 931} 932 933HIDDEN void 934dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) 935{ 936 return; /* always a nop */ 937} 938