blob: 844cc1c98a63e1289e4cfa3b93132ff54c805944 [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>
Arun Sharma1787a2f2010-05-15 12:14:09 -070028#include <sys/param.h>
mostang.com!davidm824d6612003-02-08 10:10:59 +000029
hp.com!davidm379fb062005-05-20 09:48:08 +000030#include "libunwind_i.h"
mostang.com!davidm824d6612003-02-08 10:10:59 +000031
mostang.com!davidm824d6612003-02-08 10:10:59 +000032static int
David Mosberger-Tange6b9f352007-08-22 13:02:09 -060033elf_w (lookup_symbol) (unw_addr_space_t as,
34 unw_word_t ip, struct elf_image *ei,
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000035 Elf_W (Addr) load_offset,
36 char *buf, size_t buf_len, unw_word_t *offp)
mostang.com!davidm824d6612003-02-08 10:10:59 +000037{
hp.com!davidmdee53d72003-11-27 06:52:54 +000038 size_t syment_size;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000039 Elf_W (Ehdr) *ehdr = ei->image;
40 Elf_W (Sym) *sym, *symtab, *symtab_end;
41 Elf_W (Off) soff, str_soff;
42 Elf_W (Shdr) *shdr, *str_shdr;
43 Elf_W (Addr) val, min_dist = ~(Elf_W (Addr))0;
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +000044 int i, ret = 0;
mostang.com!davidm824d6612003-02-08 10:10:59 +000045 char *strtab;
mostang.com!davidm824d6612003-02-08 10:10:59 +000046
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000047 if (!elf_w (valid_object) (ei))
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +000048 return -UNW_ENOINFO;
mostang.com!davidm824d6612003-02-08 10:10:59 +000049
50 soff = ehdr->e_shoff;
51 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size)
52 {
hp.com!davidmc67d3452004-01-30 00:01:24 +000053 Debug (1, "section table outside of image? (%lu > %lu)\n",
hp.com!davidm71650252003-09-25 05:29:14 +000054 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize),
55 (unsigned long) ei->size);
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +000056 return -UNW_ENOINFO;
mostang.com!davidm824d6612003-02-08 10:10:59 +000057 }
58
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000059 shdr = (Elf_W (Shdr) *) ((char *) ei->image + soff);
mostang.com!davidm824d6612003-02-08 10:10:59 +000060
61 for (i = 0; i < ehdr->e_shnum; ++i)
62 {
63 switch (shdr->sh_type)
64 {
65 case SHT_SYMTAB:
66 case SHT_DYNSYM:
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000067 symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset);
68 symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size);
mostang.com!davidm824d6612003-02-08 10:10:59 +000069 syment_size = shdr->sh_entsize;
70
71 str_soff = soff + (shdr->sh_link * ehdr->e_shentsize);
72 if (str_soff + ehdr->e_shentsize >= ei->size)
73 {
hp.com!davidmc67d3452004-01-30 00:01:24 +000074 Debug (1, "string table outside of image? (%lu >= %lu)\n",
hp.com!davidm71650252003-09-25 05:29:14 +000075 (unsigned long) (str_soff + ehdr->e_shentsize),
76 (unsigned long) ei->size);
mostang.com!davidm824d6612003-02-08 10:10:59 +000077 break;
78 }
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000079 str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff);
mostang.com!davidm824d6612003-02-08 10:10:59 +000080 strtab = (char *) ei->image + str_shdr->sh_offset;
81
hp.com!davidmc67d3452004-01-30 00:01:24 +000082 Debug (16, "symtab=0x%lx[%d], strtab=0x%lx\n",
hp.com!davidm71650252003-09-25 05:29:14 +000083 (long) shdr->sh_offset, shdr->sh_type,
84 (long) str_shdr->sh_offset);
mostang.com!davidm824d6612003-02-08 10:10:59 +000085
86 for (sym = symtab;
87 sym < symtab_end;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000088 sym = (Elf_W (Sym) *) ((char *) sym + syment_size))
mostang.com!davidm824d6612003-02-08 10:10:59 +000089 {
hp.com!davidm4fafd8c2003-12-20 11:23:44 +000090 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC
mostang.com!davidm824d6612003-02-08 10:10:59 +000091 && sym->st_shndx != SHN_UNDEF)
92 {
David Mosberger-Tange6b9f352007-08-22 13:02:09 -060093 if (tdep_get_func_addr (as, sym->st_value, &val) < 0)
94 continue;
mostang.com!davidm824d6612003-02-08 10:10:59 +000095 if (sym->st_shndx != SHN_ABS)
96 val += load_offset;
hp.com!davidmc67d3452004-01-30 00:01:24 +000097 Debug (16, "0x%016lx info=0x%02x %s\n",
hp.com!davidm71650252003-09-25 05:29:14 +000098 (long) val, sym->st_info, strtab + sym->st_name);
mostang.com!davidm824d6612003-02-08 10:10:59 +000099
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000100 if ((Elf_W (Addr)) (ip - val) < min_dist)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000101 {
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000102 min_dist = (Elf_W (Addr)) (ip - val);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000103 strncpy (buf, strtab + sym->st_name, buf_len);
104 buf[buf_len - 1] = '\0';
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +0000105 if (strlen (strtab + sym->st_name) >= buf_len)
106 ret = -UNW_ENOMEM;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000107 }
108 }
109 }
110 break;
111
112 default:
113 break;
114 }
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000115 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000116 }
117 if (min_dist >= ei->size)
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +0000118 return -UNW_ENOINFO; /* not found */
mostang.com!davidm824d6612003-02-08 10:10:59 +0000119 if (offp)
120 *offp = min_dist;
mostang.com!davidm7bfbbb62003-03-19 19:25:18 +0000121 return ret;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000122}
123
124/* Find the ELF image that contains IP and return the "closest"
125 procedure name, if there is one. With some caching, this could be
126 sped up greatly, but until an application materializes that's
127 sensitive to the performance of this routine, why bother... */
128
hp.com!davidm5d8b2e32005-05-03 09:13:17 +0000129HIDDEN int
Arun Sharmad276b7a2012-03-12 18:45:50 -0700130elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei,
131 unsigned long segbase,
132 unsigned long mapoff,
133 unw_word_t ip,
David Mosberger-Tange6b9f352007-08-22 13:02:09 -0600134 char *buf, size_t buf_len, unw_word_t *offp)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000135{
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000136 Elf_W (Addr) load_offset = 0;
hp.com!davidm4fafd8c2003-12-20 11:23:44 +0000137 Elf_W (Ehdr) *ehdr;
138 Elf_W (Phdr) *phdr;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000139 int i, ret;
140
Arun Sharmad276b7a2012-03-12 18:45:50 -0700141 ehdr = ei->image;
142 phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000143
144 for (i = 0; i < ehdr->e_phnum; ++i)
145 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff)
146 {
147 load_offset = segbase - phdr[i].p_vaddr;
148 break;
149 }
150
Arun Sharmad276b7a2012-03-12 18:45:50 -0700151 ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp);
152
153 return ret;
154}
155
156HIDDEN int
157elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
158 char *buf, size_t buf_len, unw_word_t *offp)
159{
160 unsigned long segbase, mapoff;
161 struct elf_image ei;
162 int ret;
163
164 ret = tdep_get_elf_image (&ei, pid, ip, &segbase, &mapoff, NULL, 0);
165 if (ret < 0)
166 return ret;
167
168 ret = elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp);
mostang.com!davidm824d6612003-02-08 10:10:59 +0000169
170 munmap (ei.image, ei.size);
171 ei.image = NULL;
172
173 return ret;
174}