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