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