1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2003-2005 Hewlett-Packard Co
3 Copyright (C) 2007 David Mosberger-Tang
4 Contributed by David Mosberger-Tang <dmosberger@gmail.com>
5
6 This file is part of libunwind.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
26
27 #include "libunwind_i.h"
28
29 #include <stdio.h>
30 #include <sys/param.h>
31
32 #ifdef HAVE_LZMA
33 #include <lzma.h>
34 #endif /* HAVE_LZMA */
35
Elf_W(Shdr)36 static Elf_W (Shdr)*
37 elf_w (section_table) (struct elf_image *ei)
38 {
39 Elf_W (Ehdr) *ehdr = ei->image;
40 Elf_W (Off) soff;
41
42 soff = ehdr->e_shoff;
43 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size)
44 {
45 Debug (1, "section table outside of image? (%lu > %lu)\n",
46 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize),
47 (unsigned long) ei->size);
48 return NULL;
49 }
50
51 return (Elf_W (Shdr) *) ((char *) ei->image + soff);
52 }
53
54 static char*
elf_w(string_table)55 elf_w (string_table) (struct elf_image *ei, int section)
56 {
57 Elf_W (Ehdr) *ehdr = ei->image;
58 Elf_W (Off) soff, str_soff;
59 Elf_W (Shdr) *str_shdr;
60
61 /* this offset is assumed to be OK */
62 soff = ehdr->e_shoff;
63
64 str_soff = soff + (section * ehdr->e_shentsize);
65 if (str_soff + ehdr->e_shentsize > ei->size)
66 {
67 Debug (1, "string shdr table outside of image? (%lu > %lu)\n",
68 (unsigned long) (str_soff + ehdr->e_shentsize),
69 (unsigned long) ei->size);
70 return NULL;
71 }
72 str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff);
73
74 if (str_shdr->sh_offset + str_shdr->sh_size > ei->size)
75 {
76 Debug (1, "string table outside of image? (%lu > %lu)\n",
77 (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size),
78 (unsigned long) ei->size);
79 return NULL;
80 }
81
82 Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset);
83 /* End of ANDROID update. */
84 return (char*) ((uintptr_t) ei->image + str_shdr->sh_offset);
85 /* End of ANDROID update. */
86 }
87
88 static int
elf_w(lookup_symbol)89 elf_w (lookup_symbol) (unw_addr_space_t as,
90 unw_word_t ip, struct elf_image *ei,
91 Elf_W (Addr) load_offset,
92 char *buf, size_t buf_len, Elf_W (Addr) *min_dist)
93 {
94 size_t syment_size;
95 Elf_W (Ehdr) *ehdr = ei->image;
96 Elf_W (Sym) *sym, *symtab, *symtab_end;
97 Elf_W (Shdr) *shdr;
98 Elf_W (Addr) val;
99 int i, ret = -UNW_ENOINFO;
100 char *strtab;
101
102 if (!elf_w (valid_object) (ei))
103 return -UNW_ENOINFO;
104
105 shdr = elf_w (section_table) (ei);
106 if (!shdr)
107 return -UNW_ENOINFO;
108
109 for (i = 0; i < ehdr->e_shnum; ++i)
110 {
111 switch (shdr->sh_type)
112 {
113 case SHT_SYMTAB:
114 case SHT_DYNSYM:
115 symtab = (Elf_W (Sym) *) ((char *) ei->image + shdr->sh_offset);
116 symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size);
117 syment_size = shdr->sh_entsize;
118
119 strtab = elf_w (string_table) (ei, shdr->sh_link);
120 if (!strtab)
121 break;
122
123 Debug (16, "symtab=0x%lx[%d]\n",
124 (long) shdr->sh_offset, shdr->sh_type);
125
126 for (sym = symtab;
127 sym < symtab_end;
128 sym = (Elf_W (Sym) *) ((char *) sym + syment_size))
129 {
130 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC
131 && sym->st_shndx != SHN_UNDEF)
132 {
133 if (tdep_get_func_addr (as, sym->st_value, &val) < 0)
134 continue;
135 if (sym->st_shndx != SHN_ABS)
136 val += load_offset;
137 Debug (16, "0x%016lx info=0x%02x %s\n",
138 (long) val, sym->st_info, strtab + sym->st_name);
139
140 /* ANDROID support update */
141 if ((Elf_W (Addr)) (ip - val) < *min_dist
142 && (Elf_W (Addr)) (ip - val) < sym->st_size)
143 /* End of ANDROID update */
144 {
145 *min_dist = (Elf_W (Addr)) (ip - val);
146 strncpy (buf, strtab + sym->st_name, buf_len);
147 buf[buf_len - 1] = '\0';
148 ret = (strlen (strtab + sym->st_name) >= buf_len
149 ? -UNW_ENOMEM : 0);
150 }
151 }
152 }
153 break;
154
155 default:
156 break;
157 }
158 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
159 }
160 return ret;
161 }
162
163 static Elf_W (Addr)
elf_w(get_load_offset)164 elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase,
165 unsigned long mapoff)
166 {
167 Elf_W (Addr) offset = 0;
168 Elf_W (Ehdr) *ehdr;
169 Elf_W (Phdr) *phdr;
170 int i;
171
172 ehdr = ei->image;
173 phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff);
174
175 for (i = 0; i < ehdr->e_phnum; ++i)
176 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff)
177 {
178 offset = segbase - phdr[i].p_vaddr;
179 break;
180 }
181
182 return offset;
183 }
184
185 #if HAVE_LZMA
186 static size_t
xz_uncompressed_size(uint8_t * compressed,size_t length)187 xz_uncompressed_size (uint8_t *compressed, size_t length)
188 {
189 uint64_t memlimit = UINT64_MAX;
190 size_t ret = 0, pos = 0;
191 lzma_stream_flags options;
192 lzma_index *index;
193
194 if (length < LZMA_STREAM_HEADER_SIZE)
195 return 0;
196
197 uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE;
198 if (lzma_stream_footer_decode (&options, footer) != LZMA_OK)
199 return 0;
200
201 if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size)
202 return 0;
203
204 uint8_t *indexdata = footer - options.backward_size;
205 if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata,
206 &pos, options.backward_size) != LZMA_OK)
207 return 0;
208
209 if (lzma_index_size (index) == options.backward_size)
210 {
211 ret = lzma_index_uncompressed_size (index);
212 }
213
214 lzma_index_end (index, NULL);
215 return ret;
216 }
217
218 static int
elf_w(extract_minidebuginfo)219 elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi)
220 {
221 Elf_W (Ehdr) *ehdr = ei->image;
222 Elf_W (Shdr) *shdr;
223 char *strtab;
224 int i;
225 uint8_t *compressed = NULL;
226 uint64_t memlimit = UINT64_MAX; /* no memory limit */
227 size_t compressed_len, uncompressed_len;
228
229 if (!elf_w (valid_object) (ei))
230 return 0;
231
232 shdr = elf_w (section_table) (ei);
233 if (!shdr)
234 return 0;
235
236 strtab = elf_w (string_table) (ei, ehdr->e_shstrndx);
237 if (!strtab)
238 return 0;
239
240 for (i = 0; i < ehdr->e_shnum; ++i)
241 {
242 if (strcmp (strtab + shdr->sh_name, ".gnu_debugdata") == 0)
243 {
244 if (shdr->sh_offset + shdr->sh_size > ei->size)
245 {
246 Debug (1, ".gnu_debugdata outside image? (0x%lu > 0x%lu)\n",
247 (unsigned long) shdr->sh_offset + shdr->sh_size,
248 (unsigned long) ei->size);
249 return 0;
250 }
251
252 Debug (16, "found .gnu_debugdata at 0x%lx\n",
253 (unsigned long) shdr->sh_offset);
254 compressed = ((uint8_t *) ei->image) + shdr->sh_offset;
255 compressed_len = shdr->sh_size;
256 break;
257 }
258
259 shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
260 }
261
262 /* not found */
263 if (!compressed)
264 return 0;
265
266 uncompressed_len = xz_uncompressed_size (compressed, compressed_len);
267 if (uncompressed_len == 0)
268 {
269 Debug (1, "invalid .gnu_debugdata contents\n");
270 return 0;
271 }
272
273 mdi->size = uncompressed_len;
274 mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE,
275 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
276
277 if (mdi->image == MAP_FAILED)
278 return 0;
279
280 size_t in_pos = 0, out_pos = 0;
281 lzma_ret lret;
282 lret = lzma_stream_buffer_decode (&memlimit, 0, NULL,
283 compressed, &in_pos, compressed_len,
284 mdi->image, &out_pos, mdi->size);
285 if (lret != LZMA_OK)
286 {
287 Debug (1, "LZMA decompression failed: %d\n", lret);
288 munmap (mdi->image, mdi->size);
289 return 0;
290 }
291
292 return 1;
293 }
294 #else
295 static int
elf_w(extract_minidebuginfo)296 elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi)
297 {
298 return 0;
299 }
300 #endif /* !HAVE_LZMA */
301
302 /* Find the ELF image that contains IP and return the "closest"
303 procedure name, if there is one. With some caching, this could be
304 sped up greatly, but until an application materializes that's
305 sensitive to the performance of this routine, why bother... */
306
307 HIDDEN int
elf_w(get_proc_name_in_image)308 elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei,
309 unsigned long segbase,
310 unsigned long mapoff,
311 unw_word_t ip,
312 char *buf, size_t buf_len, unw_word_t *offp)
313 {
314 Elf_W (Addr) load_offset;
315 Elf_W (Addr) min_dist = ~(Elf_W (Addr))0;
316 int ret;
317
318 load_offset = elf_w (get_load_offset) (ei, segbase, mapoff);
319 ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, &min_dist);
320
321 /* If the ELF image has MiniDebugInfo embedded in it, look up the symbol in
322 there as well and replace the previously found if it is closer. */
323 struct elf_image mdi;
324 if (elf_w (extract_minidebuginfo) (ei, &mdi))
325 {
326 int ret_mdi;
327
328 load_offset = elf_w (get_load_offset) (&mdi, segbase, mapoff);
329 ret_mdi = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf,
330 buf_len, &min_dist);
331
332 /* Closer symbol was found (possibly truncated). */
333 if (ret_mdi == 0 || ret_mdi == -UNW_ENOMEM)
334 {
335 ret = ret_mdi;
336 }
337
338 munmap (mdi.image, mdi.size);
339 }
340
341 if (min_dist >= ei->size)
342 return -UNW_ENOINFO; /* not found */
343 if (offp)
344 *offp = min_dist;
345 return ret;
346 }
347
348 /* ANDROID support update. */
349 HIDDEN int
elf_w(get_proc_name)350 elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
351 char *buf, size_t buf_len, unw_word_t *offp)
352 {
353 unsigned long segbase, mapoff;
354 struct elf_image ei;
355 int ret;
356
357 ret = tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL);
358 if (ret < 0)
359 return ret;
360
361 return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp);
362 }
363 /* ANDROID support update. */
364