19507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma/* libunwind - a platform-independent unwind library 29507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Copyright (C) 2003-2004 Hewlett-Packard Co 39507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 49507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 59507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaThis file is part of libunwind. 69507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 79507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaPermission is hereby granted, free of charge, to any person obtaining 89507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmaa copy of this software and associated documentation files (the 99507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma"Software"), to deal in the Software without restriction, including 109507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmawithout limitation the rights to use, copy, modify, merge, publish, 119507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmadistribute, sublicense, and/or sell copies of the Software, and to 129507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmapermit persons to whom the Software is furnished to do so, subject to 139507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmathe following conditions: 149507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 159507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaThe above copyright notice and this permission notice shall be 169507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmaincluded in all copies or substantial portions of the Software. 179507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 189507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 199507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 209507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 219507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 229507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 239507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 249507a9b5018b8be16d2b62531715f1d1e2999f4aArun SharmaWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 259507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include <elf.h> 269507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include <fcntl.h> 279507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include <string.h> 289507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include <unistd.h> 299507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 309507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include <sys/mman.h> 319507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 329507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include "libunwind_i.h" 339507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma#include "elf64.h" 349507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 359507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmastatic unw_word_t 369507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmafind_gp (struct elf_dyn_info *edi, Elf64_Phdr *pdyn, Elf64_Addr load_base) 379507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma{ 389507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Off soff, str_soff; 399507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Ehdr *ehdr = edi->ei.image; 409507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Shdr *shdr; 419507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Shdr *str_shdr; 429507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Addr gp = 0; 439507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma char *strtab; 449507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma int i; 459507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 469507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (pdyn) 479507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 489507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma /* If we have a PT_DYNAMIC program header, fetch the gp-value 499507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma from the DT_PLTGOT entry. */ 509507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Dyn *dyn = (Elf64_Dyn *) (pdyn->p_offset + (char *) edi->ei.image); 519507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma for (; dyn->d_tag != DT_NULL; ++dyn) 529507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (dyn->d_tag == DT_PLTGOT) 539507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 549507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma gp = (Elf64_Addr) dyn->d_un.d_ptr + load_base; 559507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma goto done; 569507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 579507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 589507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 599507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma /* Without a PT_DYAMIC header, lets try to look for a non-empty .opd 609507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma section. If there is such a section, we know it's full of 619507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma function descriptors, and we can simply pick up the gp from the 629507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma second word of the first entry in this table. */ 639507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 649507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma soff = ehdr->e_shoff; 659507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma str_soff = soff + (ehdr->e_shstrndx * ehdr->e_shentsize); 669507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 679507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (soff + ehdr->e_shnum * ehdr->e_shentsize > edi->ei.size) 689507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 699507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Debug (1, "section table outside of image? (%lu > %lu)", 709507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma soff + ehdr->e_shnum * ehdr->e_shentsize, 719507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->ei.size); 729507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma goto done; 739507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 749507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 759507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma shdr = (Elf64_Shdr *) ((char *) edi->ei.image + soff); 769507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma str_shdr = (Elf64_Shdr *) ((char *) edi->ei.image + str_soff); 779507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma strtab = (char *) edi->ei.image + str_shdr->sh_offset; 789507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma for (i = 0; i < ehdr->e_shnum; ++i) 799507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 809507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (strcmp (strtab + shdr->sh_name, ".opd") == 0 819507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma && shdr->sh_size >= 16) 829507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 839507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma gp = ((Elf64_Addr *) ((char *) edi->ei.image + shdr->sh_offset))[1]; 849507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma goto done; 859507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 869507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma shdr = (Elf64_Shdr *) (((char *) shdr) + ehdr->e_shentsize); 879507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 889507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 899507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma done: 909507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Debug (16, "image at %p, gp = %lx\n", edi->ei.image, gp); 919507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma return gp; 929507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma} 939507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 949507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmaint 959507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharmaia64_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, 969507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma char *path, unw_word_t segbase, unw_word_t mapoff, 979507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma unw_word_t ip) 989507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma{ 999507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Phdr *phdr, *ptxt = NULL, *punw = NULL, *pdyn = NULL; 1009507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma Elf64_Ehdr *ehdr; 1019507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma int i; 1029507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1039507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (!_Uelf64_valid_object (&edi->ei)) 1049507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma return -UNW_ENOINFO; 1059507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1069507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma ehdr = edi->ei.image; 1079507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma phdr = (Elf64_Phdr *) ((char *) edi->ei.image + ehdr->e_phoff); 1089507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1099507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma for (i = 0; i < ehdr->e_phnum; ++i) 1109507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 1119507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma switch (phdr[i].p_type) 1129507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma { 1139507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma case PT_LOAD: 1149507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (phdr[i].p_offset == mapoff) 1159507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma ptxt = phdr + i; 1169507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma break; 1179507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1189507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma case PT_IA_64_UNWIND: 1199507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma punw = phdr + i; 1209507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma break; 1219507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1229507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma case PT_DYNAMIC: 1239507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma pdyn = phdr + i; 1249507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma break; 1259507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1269507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma default: 1279507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma break; 1289507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 1299507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma } 1309507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma if (!ptxt || !punw) 1319507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma return 0; 1329507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma 1339507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.start_ip = segbase; 1349507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.end_ip = edi->di_cache.start_ip + ptxt->p_memsz; 1359507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.gp = find_gp (edi, pdyn, segbase - ptxt->p_vaddr); 1369507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.format = UNW_INFO_FORMAT_TABLE; 1379507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.u.ti.name_ptr = 0; 1389507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.u.ti.segbase = segbase; 1399507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.u.ti.table_len = punw->p_memsz / sizeof (unw_word_t); 1409507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma edi->di_cache.u.ti.table_data = (unw_word_t *) 1419507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma ((char *) edi->ei.image + (punw->p_vaddr - ptxt->p_vaddr)); 1429507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma return 1; 1439507a9b5018b8be16d2b62531715f1d1e2999f4aArun Sharma} 144