Gfind_proc_info-lsb.c revision 43e5ee28c00813fb53f6642304b33a49b70b6d62
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; 548 Elf_W(Addr) load_base, 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#ifdef CONFIG_DEBUG_FRAME 556 unw_word_t start, end; 557#endif /* CONFIG_DEBUG_FRAME*/ 558 559 ip = cb_data->ip; 560 561 /* Make sure struct dl_phdr_info is at least as big as we need. */ 562 if (size < offsetof (struct dl_phdr_info, dlpi_phnum) 563 + sizeof (info->dlpi_phnum)) 564 return -1; 565 566 Debug (15, "checking %s, base=0x%lx)\n", 567 info->dlpi_name, (long) info->dlpi_addr); 568 569 phdr = info->dlpi_phdr; 570 load_base = info->dlpi_addr; 571 p_text = NULL; 572 p_eh_hdr = NULL; 573 p_dynamic = NULL; 574 575 /* See if PC falls into one of the loaded segments. Find the 576 eh-header segment at the same time. */ 577 for (n = info->dlpi_phnum; --n >= 0; phdr++) 578 { 579 if (phdr->p_type == PT_LOAD) 580 { 581 Elf_W(Addr) vaddr = phdr->p_vaddr + load_base; 582 583 if (ip >= vaddr && ip < vaddr + phdr->p_memsz) 584 p_text = phdr; 585 586 if (vaddr + phdr->p_filesz > max_load_addr) 587 max_load_addr = vaddr + phdr->p_filesz; 588 } 589 else if (phdr->p_type == PT_GNU_EH_FRAME) 590 p_eh_hdr = phdr; 591 else if (phdr->p_type == PT_DYNAMIC) 592 p_dynamic = phdr; 593 } 594 595 if (!p_text) 596 return 0; 597 598 if (p_eh_hdr) 599 { 600 if (p_dynamic) 601 { 602 /* For dynamicly linked executables and shared libraries, 603 DT_PLTGOT is the value that data-relative addresses are 604 relative to for that object. We call this the "gp". */ 605 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base); 606 for (; dyn->d_tag != DT_NULL; ++dyn) 607 if (dyn->d_tag == DT_PLTGOT) 608 { 609 /* Assume that _DYNAMIC is writable and GLIBC has 610 relocated it (true for x86 at least). */ 611 di->gp = dyn->d_un.d_ptr; 612 break; 613 } 614 } 615 else 616 /* Otherwise this is a static executable with no _DYNAMIC. Assume 617 that data-relative addresses are relative to 0, i.e., 618 absolute. */ 619 di->gp = 0; 620 pi->gp = di->gp; 621 622 hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base); 623 if (hdr->version != DW_EH_VERSION) 624 { 625 Debug (1, "table `%s' has unexpected version %d\n", 626 info->dlpi_name, hdr->version); 627 return 0; 628 } 629 630 a = unw_get_accessors (unw_local_addr_space); 631 addr = (unw_word_t) (uintptr_t) (hdr + 1); 632 633 /* (Optionally) read eh_frame_ptr: */ 634 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, 635 &addr, hdr->eh_frame_ptr_enc, pi, 636 &eh_frame_start, NULL)) < 0) 637 return ret; 638 639 /* (Optionally) read fde_count: */ 640 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a, 641 &addr, hdr->fde_count_enc, pi, 642 &fde_count, NULL)) < 0) 643 return ret; 644 645 if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) 646 { 647 /* If there is no search table or it has an unsupported 648 encoding, fall back on linear search. */ 649 if (hdr->table_enc == DW_EH_PE_omit) 650 Debug (4, "table `%s' lacks search table; doing linear search\n", 651 info->dlpi_name); 652 else 653 Debug (4, "table `%s' has encoding 0x%x; doing linear search\n", 654 info->dlpi_name, hdr->table_enc); 655 656 eh_frame_end = max_load_addr; /* XXX can we do better? */ 657 658 if (hdr->fde_count_enc == DW_EH_PE_omit) 659 fde_count = ~0UL; 660 if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit) 661 abort (); 662 663 /* XXX we know how to build a local binary search table for 664 .debug_frame, so we could do that here too. */ 665 cb_data->single_fde = 1; 666 found = linear_search (unw_local_addr_space, ip, 667 eh_frame_start, eh_frame_end, fde_count, 668 pi, need_unwind_info, NULL); 669 if (found != 1) 670 found = 0; 671 } 672 else 673 { 674 di->format = UNW_INFO_FORMAT_REMOTE_TABLE; 675 di->start_ip = p_text->p_vaddr + load_base; 676 di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz; 677 di->u.rti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name; 678 di->u.rti.table_data = addr; 679 assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0); 680 di->u.rti.table_len = (fde_count * sizeof (struct table_entry) 681 / sizeof (unw_word_t)); 682 /* For the binary-search table in the eh_frame_hdr, data-relative 683 means relative to the start of that section... */ 684 di->u.rti.segbase = (unw_word_t) (uintptr_t) hdr; 685 686 found = 1; 687 Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, " 688 "table_data=0x%lx\n", (char *) (uintptr_t) di->u.rti.name_ptr, 689 (long) di->u.rti.segbase, (long) di->u.rti.table_len, 690 (long) di->gp, (long) di->u.rti.table_data); 691 } 692 } 693 694#ifdef CONFIG_DEBUG_FRAME 695 /* Find the start/end of the described region by parsing the phdr_info 696 structure. */ 697 start = (unw_word_t) -1; 698 end = 0; 699 700 for (n = 0; n < info->dlpi_phnum; n++) 701 { 702 if (info->dlpi_phdr[n].p_type == PT_LOAD) 703 { 704 unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr; 705 unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz; 706 707 if (seg_start < start) 708 start = seg_start; 709 710 if (seg_end > end) 711 end = seg_end; 712 } 713 } 714 715 found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip, 716 info->dlpi_addr, info->dlpi_name, start, 717 end); 718#endif /* CONFIG_DEBUG_FRAME */ 719 720 return found; 721} 722 723HIDDEN int 724dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip, 725 unw_proc_info_t *pi, int need_unwind_info, void *arg) 726{ 727 struct dwarf_callback_data cb_data; 728 intrmask_t saved_mask; 729 int ret; 730 731 Debug (14, "looking for IP=0x%lx\n", (long) ip); 732 733 memset (&cb_data, 0, sizeof (cb_data)); 734 cb_data.ip = ip; 735 cb_data.pi = pi; 736 cb_data.need_unwind_info = need_unwind_info; 737 cb_data.di.format = -1; 738 cb_data.di_debug.format = -1; 739 740 SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask); 741 ret = dl_iterate_phdr (dwarf_callback, &cb_data); 742 SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL); 743 744 if (ret <= 0) 745 { 746 Debug (14, "IP=0x%lx not found\n", (long) ip); 747 return -UNW_ENOINFO; 748 } 749 750 if (cb_data.single_fde) 751 /* already got the result in *pi */ 752 return 0; 753 754 /* search the table: */ 755 if (cb_data.di.format != -1) 756 ret = dwarf_search_unwind_table (as, ip, &cb_data.di, 757 pi, need_unwind_info, arg); 758 else 759 ret = -UNW_ENOINFO; 760 761 if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1) 762 ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi, 763 need_unwind_info, arg); 764 return ret; 765} 766 767static inline const struct table_entry * 768lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip) 769{ 770 unsigned long table_len = table_size / sizeof (struct table_entry); 771 const struct table_entry *e = 0; 772 unsigned long lo, hi, mid; 773 774 /* do a binary search for right entry: */ 775 for (lo = 0, hi = table_len; lo < hi;) 776 { 777 mid = (lo + hi) / 2; 778 e = table + mid; 779 Debug (15, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset); 780 if (rel_ip < e->start_ip_offset) 781 hi = mid; 782 else 783 lo = mid + 1; 784 } 785 if (hi <= 0) 786 return NULL; 787 e = table + hi - 1; 788 return e; 789} 790 791#endif /* !UNW_REMOTE_ONLY */ 792 793#ifndef UNW_LOCAL_ONLY 794 795/* Lookup an unwind-table entry in remote memory. Returns 1 if an 796 entry is found, 0 if no entry is found, negative if an error 797 occurred reading remote memory. */ 798static int 799remote_lookup (unw_addr_space_t as, 800 unw_word_t table, size_t table_size, int32_t rel_ip, 801 struct table_entry *e, void *arg) 802{ 803 unsigned long table_len = table_size / sizeof (struct table_entry); 804 unw_accessors_t *a = unw_get_accessors (as); 805 unsigned long lo, hi, mid; 806 unw_word_t e_addr = 0; 807 int32_t start; 808 int ret; 809 810 /* do a binary search for right entry: */ 811 for (lo = 0, hi = table_len; lo < hi;) 812 { 813 mid = (lo + hi) / 2; 814 e_addr = table + mid * sizeof (struct table_entry); 815 if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0) 816 return ret; 817 818 if (rel_ip < start) 819 hi = mid; 820 else 821 lo = mid + 1; 822 } 823 if (hi <= 0) 824 return 0; 825 e_addr = table + (hi - 1) * sizeof (struct table_entry); 826 if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0 827 || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0) 828 return ret; 829 return 1; 830} 831 832#endif /* !UNW_LOCAL_ONLY */ 833 834PROTECTED int 835dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip, 836 unw_dyn_info_t *di, unw_proc_info_t *pi, 837 int need_unwind_info, void *arg) 838{ 839 const struct table_entry *e = NULL, *table; 840 unw_word_t segbase = 0, fde_addr; 841 unw_accessors_t *a; 842#ifndef UNW_LOCAL_ONLY 843 struct table_entry ent; 844#endif 845 int ret; 846 unw_word_t debug_frame_base; 847 size_t table_len; 848 849#ifdef UNW_REMOTE_ONLY 850 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE); 851#else 852 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE 853 || di->format == UNW_INFO_FORMAT_TABLE); 854#endif 855 assert (ip >= di->start_ip && ip < di->end_ip); 856 857 if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE) 858 { 859 table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data; 860 table_len = di->u.rti.table_len * sizeof (unw_word_t); 861 debug_frame_base = 0; 862 } 863 else 864 { 865#ifndef UNW_REMOTE_ONLY 866 struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data; 867 868 /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address 869 space. Both the index and the unwind tables live in local memory, but 870 the address space to check for properties like the address size and 871 endianness is the target one. */ 872 as = unw_local_addr_space; 873 table = fdesc->index; 874 table_len = fdesc->index_size * sizeof (struct table_entry); 875 debug_frame_base = (uintptr_t) fdesc->debug_frame; 876#endif 877 } 878 879 a = unw_get_accessors (as); 880 881#ifndef UNW_REMOTE_ONLY 882 if (as == unw_local_addr_space) 883 { 884 segbase = di->u.rti.segbase; 885 e = lookup (table, table_len, ip - segbase); 886 } 887 else 888#endif 889 { 890#ifndef UNW_LOCAL_ONLY 891 segbase = di->u.rti.segbase; 892 if ((ret = remote_lookup (as, (uintptr_t) table, table_len, 893 ip - segbase, &ent, arg)) < 0) 894 return ret; 895 if (ret) 896 e = &ent; 897 else 898 e = NULL; /* no info found */ 899#endif 900 } 901 if (!e) 902 { 903 Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n", 904 (long) ip, (long) di->start_ip, (long) di->end_ip); 905 /* IP is inside this table's range, but there is no explicit 906 unwind info. */ 907 return -UNW_ENOINFO; 908 } 909 Debug (15, "ip=0x%lx, start_ip=0x%lx\n", 910 (long) ip, (long) (e->start_ip_offset)); 911 if (debug_frame_base) 912 fde_addr = e->fde_offset + debug_frame_base; 913 else 914 fde_addr = e->fde_offset + segbase; 915 Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, " 916 "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase, 917 (long) debug_frame_base, (long) fde_addr); 918 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi, 919 need_unwind_info, 920 debug_frame_base, arg)) < 0) 921 return ret; 922 923 /* .debug_frame uses an absolute encoding that does not know about any 924 shared library relocation. */ 925 if (di->format == UNW_INFO_FORMAT_TABLE) 926 { 927 pi->start_ip += segbase; 928 pi->end_ip += segbase; 929 pi->flags = UNW_PI_FLAG_DEBUG_FRAME; 930 } 931 932 if (ip < pi->start_ip || ip >= pi->end_ip) 933 return -UNW_ENOINFO; 934 935 return 0; 936} 937 938HIDDEN void 939dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg) 940{ 941 return; /* always a nop */ 942} 943