blob: 05b9943881e7c0aac82540f2c22f5349bfc31c3c [file] [log] [blame]
mostang.com!davidm824d6612003-02-08 10:10:59 +00001/* libunwind - a platform-independent unwind library
hp.com!davidm379fb062005-05-20 09:48:08 +00002 Copyright (C) 2003-2005 Hewlett-Packard Co
David Mosberger-Tange6b9f352007-08-22 13:02:09 -06003 Copyright (C) 2007 David Mosberger-Tang
4 Contributed by David Mosberger-Tang <dmosberger@gmail.com>
mostang.com!davidm824d6612003-02-08 10:10:59 +00005
6This file is part of libunwind.
7
8Permission is hereby granted, free of charge, to any person obtaining
9a copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sublicense, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice shall be
17included in all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
26
27#include <stdio.h>
mostang.com!davidm824d6612003-02-08 10:10:59 +000028
hp.com!davidm379fb062005-05-20 09:48:08 +000029#include "libunwind_i.h"
mostang.com!davidm824d6612003-02-08 10:10:59 +000030
hp.com!davidm5d8b2e32005-05-03 09:13:17 +000031HIDDEN int
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000032elf_w (valid_object) (struct elf_image *ei)
mostang.com!davidm824d6612003-02-08 10:10:59 +000033{
34 if (ei->size <= EI_CLASS)
35 return 0;
36
37 return (memcmp (ei->image, ELFMAG, SELFMAG) == 0
38 && ((uint8_t *) ei->image)[EI_CLASS] == ELF_CLASS);
39}
40
41
42static int
David Mosberger-Tange6b9f352007-08-22 13:02:09 -060043elf_w (lookup_symbol) (unw_addr_space_t as,
44 unw_word_t ip, struct elf_image *ei,
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000045 Elf_W (Addr) load_offset,
46 char *buf, size_t buf_len, unw_word_t *offp)
mostang.com!davidm824d6612003-02-08 10:10:59 +000047{
hp.com!davidmdee53d72003-11-27 06:52:54 +000048 size_t syment_size;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000049 Elf_W (Ehdr) *ehdr = ei->image;
50 Elf_W (Sym) *sym, *symtab, *symtab_end;
51 Elf_W (Off) soff, str_soff;
52 Elf_W (Shdr) *shdr, *str_shdr;
53 Elf_W (Addr) val, min_dist = ~(Elf_W (Addr))0;
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +000054 int i, ret = 0;
mostang.com!davidm824d6612003-02-08 10:10:59 +000055 char *strtab;
mostang.com!davidm824d6612003-02-08 10:10:59 +000056
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000057 if (!elf_w (valid_object) (ei))
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +000058 return -UNW_ENOINFO;
mostang.com!davidm824d6612003-02-08 10:10:59 +000059
60 soff = ehdr->e_shoff;
61 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size)
62 {
hp.com!davidmc67d3452004-01-30 00:01:24 +000063 Debug (1, "section table outside of image? (%lu > %lu)\n",
hp.com!davidm71650252003-09-25 05:29:14 +000064 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize),
65 (unsigned long) ei->size);
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +000066 return -UNW_ENOINFO;
mostang.com!davidm824d6612003-02-08 10:10:59 +000067 }
68
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000069 shdr = (Elf_W (Shdr) *) ((char *) ei->image + soff);
mostang.com!davidm824d6612003-02-08 10:10:59 +000070
71 for (i = 0; i < ehdr->e_shnum; ++i)
72 {
73 switch (shdr->sh_type)
74 {
75 case SHT_SYMTAB:
76 case SHT_DYNSYM:
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000077 symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset);
78 symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size);
mostang.com!davidm824d6612003-02-08 10:10:59 +000079 syment_size = shdr->sh_entsize;
80
81 str_soff = soff + (shdr->sh_link * ehdr->e_shentsize);
82 if (str_soff + ehdr->e_shentsize >= ei->size)
83 {
hp.com!davidmc67d3452004-01-30 00:01:24 +000084 Debug (1, "string table outside of image? (%lu >= %lu)\n",
hp.com!davidm71650252003-09-25 05:29:14 +000085 (unsigned long) (str_soff + ehdr->e_shentsize),
86 (unsigned long) ei->size);
mostang.com!davidm824d6612003-02-08 10:10:59 +000087 break;
88 }
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000089 str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff);
mostang.com!davidm824d6612003-02-08 10:10:59 +000090 strtab = (char *) ei->image + str_shdr->sh_offset;
91
hp.com!davidmc67d3452004-01-30 00:01:24 +000092 Debug (16, "symtab=0x%lx[%d], strtab=0x%lx\n",
hp.com!davidm71650252003-09-25 05:29:14 +000093 (long) shdr->sh_offset, shdr->sh_type,
94 (long) str_shdr->sh_offset);
mostang.com!davidm824d6612003-02-08 10:10:59 +000095
96 for (sym = symtab;
97 sym < symtab_end;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000098 sym = (Elf_W (Sym) *) ((char *) sym + syment_size))
mostang.com!davidm824d6612003-02-08 10:10:59 +000099 {
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000100 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC
mostang.com!davidm824d6612003-02-08 10:10:59 +0000101 && sym->st_shndx != SHN_UNDEF)
102 {
David Mosberger-Tange6b9f352007-08-22 13:02:09 -0600103 if (tdep_get_func_addr (as, sym->st_value, &val) < 0)
104 continue;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000105 if (sym->st_shndx != SHN_ABS)
106 val += load_offset;
hp.com!davidmc67d3452004-01-30 00:01:24 +0000107 Debug (16, "0x%016lx info=0x%02x %s\n",
hp.com!davidm71650252003-09-25 05:29:14 +0000108 (long) val, sym->st_info, strtab + sym->st_name);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000109
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000110 if ((Elf_W (Addr)) (ip - val) < min_dist)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000111 {
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000112 min_dist = (Elf_W (Addr)) (ip - val);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000113 strncpy (buf, strtab + sym->st_name, buf_len);
114 buf[buf_len - 1] = '\0';
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +0000115 if (strlen (strtab + sym->st_name) >= buf_len)
116 ret = -UNW_ENOMEM;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000117 }
118 }
119 }
120 break;
121
122 default:
123 break;
124 }
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000125 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000126 }
127 if (min_dist >= ei->size)
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +0000128 return -UNW_ENOINFO; /* not found */
mostang.com!davidm824d6612003-02-08 10:10:59 +0000129 if (offp)
130 *offp = min_dist;
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +0000131 return ret;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000132}
133
134/* Find the ELF image that contains IP and return the "closest"
135 procedure name, if there is one. With some caching, this could be
136 sped up greatly, but until an application materializes that's
137 sensitive to the performance of this routine, why bother... */
138
hp.com!davidm5d8b2e32005-05-03 09:13:17 +0000139HIDDEN int
David Mosberger-Tange6b9f352007-08-22 13:02:09 -0600140elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
141 char *buf, size_t buf_len, unw_word_t *offp)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000142{
143 unsigned long segbase, mapoff;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000144 Elf_W (Addr) load_offset = 0;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000145 struct elf_image ei;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000146 Elf_W (Ehdr) *ehdr;
147 Elf_W (Phdr) *phdr;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000148 int i, ret;
149
mostang.com!davidm03950aa2003-02-27 09:58:57 +0000150 ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000151 if (ret < 0)
152 return ret;
153
154 ehdr = ei.image;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000155 phdr = (Elf_W (Phdr) *) ((char *) ei.image + ehdr->e_phoff);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000156
157 for (i = 0; i < ehdr->e_phnum; ++i)
158 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff)
159 {
160 load_offset = segbase - phdr[i].p_vaddr;
161 break;
162 }
163
David Mosberger-Tange6b9f352007-08-22 13:02:09 -0600164 ret = elf_w (lookup_symbol) (as, ip, &ei, load_offset, buf, buf_len, offp);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000165
166 munmap (ei.image, ei.size);
167 ei.image = NULL;
168
169 return ret;
170}