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
36 // --------------------------------------------------------------------------
37 // Functions to read elf data from memory.
38 // --------------------------------------------------------------------------
elf_w(memory_read)39 extern size_t elf_w (memory_read) (
40 struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read) {
41 struct map_info* map = ei->u.memory.map;
42 unw_accessors_t* a = unw_get_accessors (ei->u.memory.as);
43 if (map->end - addr < bytes) {
44 bytes = map->end - addr;
45 }
46 size_t bytes_read = 0;
47 unw_word_t data_word;
48 size_t align_bytes = addr & (sizeof(unw_word_t) - 1);
49 if (align_bytes != 0) {
50 if ((*a->access_mem) (ei->u.memory.as, addr & ~(sizeof(unw_word_t) - 1), &data_word,
51 0, ei->u.memory.as_arg) != 0) {
52 return 0;
53 }
54 size_t copy_bytes = MIN(sizeof(unw_word_t) - align_bytes, bytes);
55 memcpy (buffer, (uint8_t*) (&data_word) + align_bytes, copy_bytes);
56 if (string_read) {
57 // Check for nul terminator.
58 uint8_t* nul_terminator = memchr (buffer, '\0', copy_bytes);
59 if (nul_terminator != NULL) {
60 return nul_terminator - buffer;
61 }
62 }
63
64 addr += copy_bytes;
65 bytes_read += copy_bytes;
66 bytes -= copy_bytes;
67 buffer += copy_bytes;
68 }
69
70 size_t num_words = bytes / sizeof(unw_word_t);
71 size_t i;
72 for (i = 0; i < num_words; i++) {
73 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) {
74 return bytes_read;
75 }
76
77 memcpy (buffer, &data_word, sizeof(unw_word_t));
78 if (string_read) {
79 // Check for nul terminator.
80 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t));
81 if (nul_terminator != NULL) {
82 return nul_terminator - buffer + bytes_read;
83 }
84 }
85
86 addr += sizeof(unw_word_t);
87 bytes_read += sizeof(unw_word_t);
88 buffer += sizeof(unw_word_t);
89 }
90
91 size_t left_over = bytes & (sizeof(unw_word_t) - 1);
92 if (left_over) {
93 if ((*a->access_mem) (ei->u.memory.as, addr, &data_word, 0, ei->u.memory.as_arg) != 0) {
94 return bytes_read;
95 }
96
97 memcpy (buffer, &data_word, left_over);
98 if (string_read) {
99 // Check for nul terminator.
100 uint8_t* nul_terminator = memchr (buffer, '\0', sizeof(unw_word_t));
101 if (nul_terminator != NULL) {
102 return nul_terminator - buffer + bytes_read;
103 }
104 }
105
106 bytes_read += left_over;
107 }
108 return bytes_read;
109 }
110
elf_w(section_table_offset)111 static bool elf_w (section_table_offset) (struct elf_image* ei, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) {
112 GET_EHDR_FIELD(ei, ehdr, e_shoff, true);
113 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true);
114 GET_EHDR_FIELD(ei, ehdr, e_shnum, true);
115
116 uintptr_t size = ei->u.memory.map->end - ei->u.memory.map->start;
117 if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) {
118 Debug (1, "section table outside of image? (%lu > %lu)\n",
119 (unsigned long) (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize),
120 (unsigned long) size);
121 return false;
122 }
123
124 *offset = ehdr->e_shoff;
125 return true;
126 }
127
elf_w(string_table_offset)128 static bool elf_w (string_table_offset) (
129 struct elf_image* ei, int section, Elf_W(Ehdr)* ehdr, Elf_W(Off)* offset) {
130 GET_EHDR_FIELD(ei, ehdr, e_shoff, true);
131 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true);
132 unw_word_t str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize);
133 uintptr_t size = ei->u.memory.map->end - ei->u.memory.map->start;
134 if (str_soff + ehdr->e_shentsize > size) {
135 Debug (1, "string shdr table outside of image? (%lu > %lu)\n",
136 (unsigned long) (str_soff + ehdr->e_shentsize),
137 (unsigned long) size);
138 return false;
139 }
140
141 Elf_W(Shdr) shdr;
142 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_offset);
143 GET_SHDR_FIELD(ei, str_soff, &shdr, sh_size);
144 if (shdr.sh_offset + shdr.sh_size > size) {
145 Debug (1, "string table outside of image? (%lu > %lu)\n",
146 (unsigned long) (shdr.sh_offset + shdr.sh_size),
147 (unsigned long) size);
148 return false;
149 }
150
151 Debug (16, "strtab=0x%lx\n", (long) shdr.sh_offset);
152 *offset = shdr.sh_offset;
153 return true;
154 }
155
elf_w(lookup_symbol_memory)156 static bool elf_w (lookup_symbol_memory) (
157 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset,
158 char* buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) {
159 Elf_W(Off) shdr_offset;
160 if (!elf_w (section_table_offset) (ei, ehdr, &shdr_offset)) {
161 return false;
162 }
163
164 GET_EHDR_FIELD(ei, ehdr, e_shnum, true);
165 GET_EHDR_FIELD(ei, ehdr, e_shentsize, true);
166 int i;
167 for (i = 0; i < ehdr->e_shnum; ++i) {
168 Elf_W(Shdr) shdr;
169 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_type);
170 switch (shdr.sh_type) {
171 case SHT_SYMTAB:
172 case SHT_DYNSYM:
173 {
174 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_link);
175
176 Elf_W(Off) strtab_offset;
177 if (!elf_w (string_table_offset) (ei, shdr.sh_link, ehdr, &strtab_offset)) {
178 continue;
179 }
180
181 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_offset);
182 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_size);
183 GET_SHDR_FIELD(ei, shdr_offset, &shdr, sh_entsize);
184
185 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr.sh_offset, shdr.sh_type);
186
187 unw_word_t sym_offset;
188 unw_word_t symtab_end = shdr.sh_offset + shdr.sh_size;
189 for (sym_offset = shdr.sh_offset;
190 sym_offset < symtab_end;
191 sym_offset += shdr.sh_entsize) {
192 Elf_W(Sym) sym;
193 GET_SYM_FIELD(ei, sym_offset, &sym, st_info);
194 GET_SYM_FIELD(ei, sym_offset, &sym, st_shndx);
195
196 if (ELF_W (ST_TYPE) (sym.st_info) == STT_FUNC && sym.st_shndx != SHN_UNDEF) {
197 GET_SYM_FIELD(ei, sym_offset, &sym, st_value);
198 Elf_W(Addr) val;
199 if (tdep_get_func_addr (as, sym.st_value, &val) < 0) {
200 continue;
201 }
202 if (sym.st_shndx != SHN_ABS) {
203 val += load_offset;
204 }
205 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym.st_info);
206
207 GET_SYM_FIELD(ei, sym_offset, &sym, st_size);
208 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym.st_size) {
209 GET_SYM_FIELD(ei, sym_offset, &sym, st_name);
210 uintptr_t size = ei->u.memory.map->end - ei->u.memory.map->start;
211 Elf_W(Off) strname_offset = strtab_offset + sym.st_name;
212 if (strname_offset > size || strname_offset < strtab_offset) {
213 // Malformed elf symbol table.
214 break;
215 }
216
217 size_t bytes_read = elf_w (memory_read) (
218 ei, ei->u.memory.map->start + strname_offset,
219 (uint8_t*) buf, buf_len, true);
220 if (bytes_read == 0) {
221 // Empty name, so keep checking the other symbol tables
222 // for a possible match.
223 break;
224 }
225 // Ensure the string is nul terminated, it is assumed that
226 // sizeof(buf) >= buf_len + 1.
227 buf[buf_len] = '\0';
228
229 if (offp != NULL) {
230 *offp = ip - val;
231 }
232 return true;
233 }
234 }
235 }
236 break;
237 }
238
239 default:
240 break;
241 }
242 shdr_offset += ehdr->e_shentsize;
243 }
244 return false;
245 }
246
elf_w(get_load_offset_memory)247 static bool elf_w (get_load_offset_memory) (
248 struct elf_image* ei, unsigned long segbase, unsigned long mapoff,
249 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) {
250 GET_EHDR_FIELD(ei, ehdr, e_phoff, true);
251 GET_EHDR_FIELD(ei, ehdr, e_phnum, true);
252
253 unw_word_t offset = ehdr->e_phoff;
254 int i;
255 for (i = 0; i < ehdr->e_phnum; ++i) {
256 Elf_W(Phdr) phdr;
257 GET_PHDR_FIELD(ei, offset, &phdr, p_type);
258 if (phdr.p_type == PT_LOAD) {
259 GET_PHDR_FIELD(ei, offset, &phdr, p_offset);
260 if (phdr.p_offset == mapoff) {
261 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr);
262 *load_offset = segbase - phdr.p_vaddr;
263 return true;
264 }
265 }
266 offset += sizeof(Elf_W(Phdr));
267 }
268 return false;
269 }
270
271 // --------------------------------------------------------------------------
272 // Functions to read elf data from the mapped elf image.
273 // --------------------------------------------------------------------------
Elf_W(Shdr)274 static Elf_W(Shdr)* elf_w (section_table) (struct elf_image* ei) {
275 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
276 Elf_W(Off) soff = ehdr->e_shoff;
277 if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->u.mapped.size) {
278 Debug (1, "section table outside of image? (%lu > %lu)\n",
279 (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize),
280 (unsigned long) ei->u.mapped.size);
281 return NULL;
282 }
283
284 return (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + soff);
285 }
286
elf_w(string_table)287 static char* elf_w (string_table) (struct elf_image* ei, int section) {
288 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
289 Elf_W(Off) str_soff = ehdr->e_shoff + (section * ehdr->e_shentsize);
290 if (str_soff + ehdr->e_shentsize > ei->u.mapped.size) {
291 Debug (1, "string shdr table outside of image? (%lu > %lu)\n",
292 (unsigned long) (str_soff + ehdr->e_shentsize),
293 (unsigned long) ei->u.mapped.size);
294 return NULL;
295 }
296 Elf_W(Shdr)* str_shdr = (Elf_W(Shdr) *) ((char *) ei->u.mapped.image + str_soff);
297
298 if (str_shdr->sh_offset + str_shdr->sh_size > ei->u.mapped.size) {
299 Debug (1, "string table outside of image? (%lu > %lu)\n",
300 (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size),
301 (unsigned long) ei->u.mapped.size);
302 return NULL;
303 }
304
305 Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset);
306 return (char*) ((uintptr_t) ei->u.mapped.image + str_shdr->sh_offset);
307 }
308
elf_w(lookup_symbol_mapped)309 static bool elf_w (lookup_symbol_mapped) (
310 unw_addr_space_t as, unw_word_t ip, struct elf_image* ei, Elf_W(Addr) load_offset,
311 char* buf, size_t buf_len, unw_word_t* offp) {
312
313 Elf_W(Shdr)* shdr = elf_w (section_table) (ei);
314 if (!shdr) {
315 return false;
316 }
317
318 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
319 int i;
320 for (i = 0; i < ehdr->e_shnum; ++i) {
321 switch (shdr->sh_type) {
322 case SHT_SYMTAB:
323 case SHT_DYNSYM:
324 {
325 Elf_W(Sym)* symtab = (Elf_W(Sym) *) ((char *) ei->u.mapped.image + shdr->sh_offset);
326 Elf_W(Sym)* symtab_end = (Elf_W(Sym) *) ((char *) symtab + shdr->sh_size);
327
328 char* strtab = elf_w (string_table) (ei, shdr->sh_link);
329 if (!strtab) {
330 continue;
331 }
332
333 Debug (16, "symtab=0x%lx[%d]\n", (long) shdr->sh_offset, shdr->sh_type);
334
335 Elf_W(Sym)* sym;
336 for (sym = symtab;
337 sym < symtab_end;
338 sym = (Elf_W(Sym) *) ((char *) sym + shdr->sh_entsize)) {
339 if (ELF_W (ST_TYPE) (sym->st_info) == STT_FUNC && sym->st_shndx != SHN_UNDEF) {
340 Elf_W(Addr) val;
341 if (tdep_get_func_addr (as, sym->st_value, &val) < 0) {
342 continue;
343 }
344 if (sym->st_shndx != SHN_ABS) {
345 val += load_offset;
346 }
347 Debug (16, "0x%016lx info=0x%02x\n", (long) val, sym->st_info);
348 if (ip >= val && (Elf_W(Addr)) (ip - val) < sym->st_size) {
349 char* str_name = strtab + sym->st_name;
350 if (str_name > (char*) ei->u.mapped.image + ei->u.mapped.size ||
351 str_name < strtab) {
352 // Malformed elf symbol table.
353 break;
354 }
355
356 // Make sure we don't try and read past the end of the image.
357 uintptr_t max_size = (uintptr_t) str_name - (uintptr_t) ei->u.mapped.image;
358 if (buf_len > max_size) {
359 buf_len = max_size;
360 }
361
362 strncpy (buf, str_name, buf_len);
363 // Ensure the string is nul terminated, it is assumed that
364 // sizeof(buf) >= buf_len + 1.
365 buf[buf_len] = '\0';
366 if (buf[0] == '\0') {
367 // Empty name, so keep checking the other symbol tables
368 // for a possible match.
369 break;
370 }
371 if (offp != NULL) {
372 *offp = ip - val;
373 }
374 return true;
375 }
376 }
377 }
378 break;
379 }
380
381 default:
382 break;
383 }
384 shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
385 }
386 return false;
387 }
388
elf_w(get_load_offset_mapped)389 static bool elf_w (get_load_offset_mapped) (
390 struct elf_image *ei, unsigned long segbase, unsigned long mapoff, Elf_W(Addr)* load_offset) {
391 Elf_W(Ehdr) *ehdr = ei->u.mapped.image;
392 Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) ((char *) ei->u.mapped.image + ehdr->e_phoff);
393
394 int i;
395 for (i = 0; i < ehdr->e_phnum; ++i) {
396 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) {
397 *load_offset = segbase - phdr[i].p_vaddr;
398 return true;
399 }
400 }
401 return false;
402 }
403
404 // --------------------------------------------------------------------------
405
elf_w(lookup_symbol)406 static inline bool elf_w (lookup_symbol) (
407 unw_addr_space_t as, unw_word_t ip, struct elf_image *ei, Elf_W(Addr) load_offset,
408 char *buf, size_t buf_len, unw_word_t* offp, Elf_W(Ehdr)* ehdr) {
409 if (!ei->valid)
410 return false;
411
412 if (buf_len <= 1) {
413 Debug (1, "lookup_symbol called with a buffer too small to hold a name %zu\n", buf_len);
414 return false;
415 }
416
417 // Leave enough space for the nul terminator.
418 buf_len--;
419
420 if (ei->mapped) {
421 return elf_w (lookup_symbol_mapped) (as, ip, ei, load_offset, buf, buf_len, offp);
422 } else {
423 return elf_w (lookup_symbol_memory) (as, ip, ei, load_offset, buf, buf_len, offp, ehdr);
424 }
425 }
426
elf_w(get_load_offset)427 static bool elf_w (get_load_offset) (
428 struct elf_image* ei, unsigned long segbase, unsigned long mapoff,
429 Elf_W(Ehdr)* ehdr, Elf_W(Addr)* load_offset) {
430 if (ei->mapped) {
431 return elf_w (get_load_offset_mapped) (ei, segbase, mapoff, load_offset);
432 } else {
433 return elf_w (get_load_offset_memory) (ei, segbase, mapoff, ehdr, load_offset);
434 }
435 }
436
437 #if HAVE_LZMA
xz_uncompressed_size(uint8_t * compressed,size_t length)438 static size_t xz_uncompressed_size (uint8_t* compressed, size_t length) {
439 uint64_t memlimit = UINT64_MAX;
440 size_t ret = 0, pos = 0;
441 lzma_stream_flags options;
442 lzma_index *index;
443
444 if (length < LZMA_STREAM_HEADER_SIZE) {
445 return 0;
446 }
447
448 uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE;
449 if (lzma_stream_footer_decode (&options, footer) != LZMA_OK) {
450 return 0;
451 }
452
453 if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size) {
454 return 0;
455 }
456
457 uint8_t* indexdata = footer - options.backward_size;
458 if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata,
459 &pos, options.backward_size) != LZMA_OK) {
460 return 0;
461 }
462
463 if (lzma_index_size (index) == options.backward_size) {
464 ret = lzma_index_uncompressed_size (index);
465 }
466
467 lzma_index_end (index, NULL);
468 return ret;
469 }
470
elf_w(extract_minidebuginfo)471 static bool elf_w (extract_minidebuginfo) (struct elf_image* ei, struct elf_image* mdi, Elf_W(Ehdr)* ehdr) {
472 Elf_W(Ehdr)* ehdr = ei->image;
473 Elf_W(Shdr)* shdr;
474 char *strtab;
475 int i;
476 uint8_t *compressed = NULL;
477 uint64_t memlimit = UINT64_MAX; /* no memory limit */
478 size_t compressed_len, uncompressed_len;
479
480 if (!ei->valid) {
481 return false;
482 }
483
484 shdr = elf_w (section_table) (ei);
485 if (!shdr) {
486 return false;
487 }
488
489 strtab = elf_w (string_table) (ei, ehdr->e_shstrndx);
490 if (!strtab) {
491 return false;
492 }
493
494 for (i = 0; i < ehdr->e_shnum; ++i) {
495 if (strcmp (strtab + shdr->sh_name, ".gnu_debugdata") == 0) {
496 if (shdr->sh_offset + shdr->sh_size > ei->size) {
497 Debug (1, ".gnu_debugdata outside image? (0x%lu > 0x%lu)\n",
498 (unsigned long) shdr->sh_offset + shdr->sh_size,
499 (unsigned long) ei->size);
500 return false;
501 }
502
503 Debug (16, "found .gnu_debugdata at 0x%lx\n",
504 (unsigned long) shdr->sh_offset);
505 compressed = ((uint8_t *) ei->image) + shdr->sh_offset;
506 compressed_len = shdr->sh_size;
507 break;
508 }
509
510 shdr = (Elf_W(Shdr) *) (((char *) shdr) + ehdr->e_shentsize);
511 }
512
513 /* not found */
514 if (!compressed) {
515 return false;
516 }
517
518 uncompressed_len = xz_uncompressed_size (compressed, compressed_len);
519 if (uncompressed_len == 0) {
520 Debug (1, "invalid .gnu_debugdata contents\n");
521 return false;
522 }
523
524 mdi->size = uncompressed_len;
525 mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE,
526 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
527
528 if (mdi->image == MAP_FAILED) {
529 return false;
530 }
531
532 size_t in_pos = 0, out_pos = 0;
533 lzma_ret lret;
534 lret = lzma_stream_buffer_decode (&memlimit, 0, NULL,
535 compressed, &in_pos, compressed_len,
536 mdi->image, &out_pos, mdi->size);
537 if (lret != LZMA_OK) {
538 Debug (1, "LZMA decompression failed: %d\n", lret);
539 munmap (mdi->image, mdi->size);
540 return false;
541 }
542
543 return true;
544 }
545 #else
elf_w(extract_minidebuginfo)546 static bool elf_w (extract_minidebuginfo) (struct elf_image* ei, struct elf_image* mdi, Elf_W(Ehdr)* ehdr) {
547 return false;
548 }
549 #endif /* !HAVE_LZMA */
550
551 // Find the ELF image that contains IP and return the procedure name from
552 // the symbol table that matches the IP.
elf_w(get_proc_name_in_image)553 HIDDEN bool elf_w (get_proc_name_in_image) (
554 unw_addr_space_t as, struct elf_image* ei, unsigned long segbase, unsigned long mapoff,
555 unw_word_t ip, char* buf, size_t buf_len, unw_word_t* offp) {
556 Elf_W(Ehdr) ehdr;
557 memset(&ehdr, 0, sizeof(ehdr));
558 Elf_W(Addr) load_offset;
559 if (!elf_w (get_load_offset) (ei, segbase, mapoff, &ehdr, &load_offset)) {
560 return false;
561 }
562
563 if (elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp, &ehdr) != 0) {
564 return true;
565 }
566
567 // If the ELF image doesn't contain a match, look up the symbol in
568 // the MiniDebugInfo.
569 struct elf_image mdi;
570 if (elf_w (extract_minidebuginfo) (ei, &mdi, &ehdr)) {
571 if (!elf_w (get_load_offset) (&mdi, segbase, mapoff, &ehdr, &load_offset)) {
572 return false;
573 }
574 if (elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, buf_len, offp, &ehdr)) {
575 munmap (mdi.u.mapped.image, mdi.u.mapped.size);
576 return true;
577 }
578 return false;
579 }
580 return false;
581 }
582
elf_w(get_proc_name)583 HIDDEN bool elf_w (get_proc_name) (
584 unw_addr_space_t as, pid_t pid, unw_word_t ip, char* buf, size_t buf_len,
585 unw_word_t* offp, void* as_arg) {
586 unsigned long segbase, mapoff;
587 struct elf_image ei;
588
589 if (tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL, as_arg) < 0) {
590 return false;
591 }
592
593 return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp);
594 }
595
elf_w(get_load_base)596 HIDDEN bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base) {
597 if (!ei->valid) {
598 return false;
599 }
600
601 if (ei->mapped) {
602 Elf_W(Ehdr)* ehdr = ei->u.mapped.image;
603 Elf_W(Phdr)* phdr = (Elf_W(Phdr)*) ((char*) ei->u.mapped.image + ehdr->e_phoff);
604 int i;
605 for (i = 0; i < ehdr->e_phnum; ++i) {
606 if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) {
607 *load_base = phdr[i].p_vaddr;
608 return true;
609 }
610 }
611 return false;
612 } else {
613 Elf_W(Ehdr) ehdr;
614 GET_EHDR_FIELD(ei, &ehdr, e_phnum, false);
615 GET_EHDR_FIELD(ei, &ehdr, e_phoff, false);
616 int i;
617 unw_word_t offset = ehdr.e_phoff;
618 for (i = 0; i < ehdr.e_phnum; ++i) {
619 Elf_W(Phdr) phdr;
620 GET_PHDR_FIELD(ei, offset, &phdr, p_type);
621 GET_PHDR_FIELD(ei, offset, &phdr, p_offset);
622 if (phdr.p_type == PT_LOAD && phdr.p_offset == mapoff) {
623 GET_PHDR_FIELD(ei, offset, &phdr, p_vaddr);
624 *load_base = phdr.p_vaddr;
625 return true;
626 }
627 offset += sizeof(phdr);
628 }
629 return false;
630 }
631 return false;
632 }
633