1 /* libunwind - a platform-independent unwind library
2 Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5 This file is part of libunwind.
6
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
26 /* Locate an FDE via the ELF data-structures defined by LSB v1.3
27 (http://www.linuxbase.org/spec/). */
28
29 #include <stddef.h>
30 #include <stdio.h>
31 #include <limits.h>
32
33 #include "dwarf_i.h"
34 #include "dwarf-eh.h"
35 #include "libunwind_i.h"
36
37 struct table_entry
38 {
39 int32_t start_ip_offset;
40 int32_t fde_offset;
41 };
42
43 #ifndef UNW_REMOTE_ONLY
44
45 #ifdef __linux
46 #include "os-linux.h"
47 #endif
48
49 static int
linear_search(unw_addr_space_t as,unw_word_t ip,unw_word_t eh_frame_start,unw_word_t eh_frame_end,unw_word_t fde_count,unw_proc_info_t * pi,int need_unwind_info,void * arg)50 linear_search (unw_addr_space_t as, unw_word_t ip,
51 unw_word_t eh_frame_start, unw_word_t eh_frame_end,
52 unw_word_t fde_count,
53 unw_proc_info_t *pi, int need_unwind_info, void *arg)
54 {
55 unw_accessors_t *a = unw_get_accessors (unw_local_addr_space);
56 unw_word_t i = 0, fde_addr, addr = eh_frame_start;
57 int ret;
58
59 while (i++ < fde_count && addr < eh_frame_end)
60 {
61 fde_addr = addr;
62 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, 0, arg))
63 < 0)
64 return ret;
65
66 if (ip >= pi->start_ip && ip < pi->end_ip)
67 {
68 if (!need_unwind_info)
69 return 1;
70 addr = fde_addr;
71 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
72 need_unwind_info, 0,
73 arg))
74 < 0)
75 return ret;
76 return 1;
77 }
78 }
79 return -UNW_ENOINFO;
80 }
81 #endif /* !UNW_REMOTE_ONLY */
82
83 #ifdef CONFIG_DEBUG_FRAME
84 /* Load .debug_frame section from FILE. Allocates and returns space
85 in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the
86 local process, in which case we can search the system debug file
87 directory; 0 for other address spaces, in which case we do not; or
88 -1 for recursive calls following .gnu_debuglink. Returns 0 on
89 success, 1 on error. Succeeds even if the file contains no
90 .debug_frame. */
91 /* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */
92
93 static int
load_debug_frame(const char * file,char ** buf,size_t * bufsize,int is_local,Elf_W (Addr)* segbase_bias)94 load_debug_frame (const char *file, char **buf, size_t *bufsize,
95 int is_local, Elf_W(Addr)* segbase_bias)
96 {
97 FILE *f;
98 Elf_W (Ehdr) ehdr;
99 Elf_W (Half) shstrndx;
100 Elf_W (Shdr) *sec_hdrs = NULL;
101 char *stringtab = NULL;
102 unsigned int i;
103 size_t linksize = 0;
104 char *linkbuf = NULL;
105
106 *buf = NULL;
107 *bufsize = 0;
108
109 f = fopen (file, "r");
110
111 if (!f)
112 return 1;
113
114 if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
115 goto file_error;
116
117 /* Verify this is actually an elf file. */
118 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0)
119 goto file_error;
120
121 shstrndx = ehdr.e_shstrndx;
122
123 Debug (4, "opened file '%s'. Section header at offset %d\n",
124 file, (int) ehdr.e_shoff);
125
126 fseek (f, ehdr.e_shoff, SEEK_SET);
127 sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
128 if (sec_hdrs == NULL || fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum
129 || shstrndx >= ehdr.e_shnum)
130 goto file_error;
131
132 Debug (4, "loading string table of size %ld\n",
133 (long) sec_hdrs[shstrndx].sh_size);
134 size_t sec_size = sec_hdrs[shstrndx].sh_size;
135 stringtab = malloc (sec_size);
136 fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
137 if (stringtab == NULL || fread (stringtab, 1, sec_size, f) != sec_size)
138 goto file_error;
139
140 for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
141 {
142 size_t sec_position = sec_hdrs[i].sh_name;
143 if (sec_position >= sec_size)
144 continue;
145 char *secname = &stringtab[sec_position];
146
147 if (sec_position + sizeof(".debug_frame") <= sec_size
148 && strcmp (secname, ".debug_frame") == 0)
149 {
150 *bufsize = sec_hdrs[i].sh_size;
151 *buf = malloc (*bufsize);
152 fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
153 if (*buf == NULL || fread (*buf, 1, *bufsize, f) != *bufsize)
154 goto file_error;
155
156 Debug (4, "read %zd bytes of .debug_frame from offset %ld\n",
157 *bufsize, (long) sec_hdrs[i].sh_offset);
158 }
159 else if (sec_position + sizeof(".gnu_debuglink") <= sec_size
160 && strcmp (secname, ".gnu_debuglink") == 0)
161 {
162 linksize = sec_hdrs[i].sh_size;
163 linkbuf = malloc (linksize);
164 fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
165 if (linkbuf == NULL || fread (linkbuf, 1, linksize, f) != linksize)
166 goto file_error;
167
168 Debug (4, "read %zd bytes of .gnu_debuglink from offset %ld\n",
169 linksize, (long) sec_hdrs[i].sh_offset);
170 }
171 /* ANDROID support update. */
172 // Do not process the compressed section for local unwinds.
173 // Uncompressing this section can consume a large amount of memory
174 // and cause the unwind to take longer, which can cause problems
175 // when an ANR occurs in the system. Compressed sections are
176 // only used to contain java stack trace information. Since ART is
177 // one of the only ways that a local trace is done, and it already
178 // dumps the java stack, this information is redundant.
179 else if (local_map_list == NULL
180 && sec_position + sizeof(".gnu_debugdata") <= sec_size
181 && strcmp (secname, ".gnu_debugdata") == 0)
182 {
183 size_t xz_size = sec_hdrs[i].sh_size;
184 uint8_t* xz_data = malloc (xz_size);
185 struct elf_image mdi;
186 if (xz_data == NULL)
187 goto file_error;
188 fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
189 if (fread (xz_data, 1, xz_size, f) != xz_size) {
190 free(xz_data);
191 goto file_error;
192 }
193 Debug (4, "read %zd bytes of .gnu_debugdata from offset %ld\n",
194 xz_size, (long) sec_hdrs[i].sh_offset);
195 if (elf_w (xz_decompress) (xz_data, xz_size,
196 (uint8_t**)&mdi.u.mapped.image, &mdi.u.mapped.size)) {
197 uint8_t* found_section;
198 Elf_W(Addr) old_text_vaddr, new_text_vaddr;
199 mdi.valid = elf_w (valid_object_mapped) (&mdi);
200 mdi.mapped = true;
201 Debug (4, "decompressed .gnu_debugdata\n");
202 if (elf_w (find_section_mapped) (&mdi, ".debug_frame", &found_section, bufsize, NULL)) {
203 Debug (4, "found .debug_frame in .gnu_debugdata\n");
204 *buf = malloc (*bufsize);
205 if (*buf == NULL) {
206 free(xz_data);
207 free(mdi.u.mapped.image);
208 goto file_error;
209 }
210 memcpy(*buf, found_section, *bufsize);
211 // The ELF file might have been relocated since .gnu_debugdata was created.
212 if (elf_w (find_section_mapped) (&mdi, ".text", NULL, NULL, &old_text_vaddr)) {
213 int j;
214 for (j = 1; j < ehdr.e_shnum; j++) {
215 if (sec_hdrs[j].sh_name + sizeof(".text") <= sec_size
216 && strcmp(&stringtab[sec_hdrs[j].sh_name], ".text") == 0) {
217 new_text_vaddr = sec_hdrs[j].sh_addr;
218 *segbase_bias = new_text_vaddr - old_text_vaddr;
219 Debug (4, "ELF file was relocated by 0x%llx bytes since it was created.\n",
220 (unsigned long long)*segbase_bias);
221 break;
222 }
223 }
224 }
225 } else {
226 Debug (1, "can not find .debug_frame inside .gnu_debugdata\n");
227 }
228 free(mdi.u.mapped.image);
229 } else {
230 Debug (1, "failed to decompress .gnu_debugdata\n");
231 }
232 free(xz_data);
233 }
234 /* End of ANDROID update. */
235 }
236
237 free (stringtab);
238 free (sec_hdrs);
239
240 fclose (f);
241
242 /* Ignore separate debug files which contain a .gnu_debuglink section. */
243 if (linkbuf && is_local == -1)
244 {
245 free (linkbuf);
246 return 1;
247 }
248
249 if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
250 {
251 char *newname, *basedir, *p;
252 static const char *debugdir = "/usr/lib/debug";
253 int ret;
254
255 /* XXX: Don't bother with the checksum; just search for the file. */
256 basedir = malloc (strlen (file) + 1);
257 newname = malloc (strlen (linkbuf) + strlen (debugdir)
258 + strlen (file) + 9);
259 if (basedir == NULL || newname == NULL)
260 goto file_error;
261
262 p = strrchr (file, '/');
263 if (p != NULL)
264 {
265 memcpy (basedir, file, p - file);
266 basedir[p - file] = '\0';
267 }
268 else
269 basedir[0] = 0;
270
271 strcpy (newname, basedir);
272 strcat (newname, "/");
273 strcat (newname, linkbuf);
274 ret = load_debug_frame (newname, buf, bufsize, -1, segbase_bias);
275
276 if (ret == 1)
277 {
278 strcpy (newname, basedir);
279 strcat (newname, "/.debug/");
280 strcat (newname, linkbuf);
281 ret = load_debug_frame (newname, buf, bufsize, -1, segbase_bias);
282 }
283
284 if (ret == 1 && is_local == 1)
285 {
286 strcpy (newname, debugdir);
287 strcat (newname, basedir);
288 strcat (newname, "/");
289 strcat (newname, linkbuf);
290 ret = load_debug_frame (newname, buf, bufsize, -1, segbase_bias);
291 }
292
293 free (basedir);
294 free (newname);
295 }
296 free (linkbuf);
297
298 return 0;
299
300 /* An error reading image file. Release resources and return error code */
301 file_error:
302 free(stringtab);
303 free(sec_hdrs);
304 free(linkbuf);
305 free(*buf);
306 fclose(f);
307
308 return 1;
309 }
310
311 /* Locate the binary which originated the contents of address ADDR. Return
312 the name of the binary in *name (space is allocated by the caller)
313 Returns 0 if a binary is successfully found, or 1 if an error occurs. */
314
315 /* ANDROID support update. */
316 /* Removed the find_binary_for_address function. */
317 /* End of ANDROID update. */
318
319 /* Locate and/or try to load a debug_frame section for address ADDR. Return
320 pointer to debug frame descriptor, or zero if not found. */
321
322 static struct unw_debug_frame_list *
locate_debug_info(unw_addr_space_t as,unw_word_t addr,const char * dlname,unw_word_t start,unw_word_t end)323 locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
324 unw_word_t start, unw_word_t end)
325 {
326 struct unw_debug_frame_list *w, *fdesc = 0;
327 int err;
328 char *buf;
329 size_t bufsize;
330 /* ANDROID support update. */
331 char *name = NULL;
332 Elf_W(Addr) segbase_bias = 0;
333 /* End of ANDROID update. */
334
335 /* First, see if we loaded this frame already. */
336
337 for (w = as->debug_frames; w; w = w->next)
338 {
339 Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end);
340 if (addr >= w->start && addr < w->end)
341 return w;
342 }
343
344 /* ANDROID support update. */
345 /* If the object name we receive is blank, there's still a chance of locating
346 the file by looking at the maps cache. */
347
348 if (strcmp (dlname, "") == 0)
349 {
350 #ifdef UNW_LOCAL_ONLY
351 name = map_local_get_image_name (addr);
352 #else
353 struct map_info *map = map_find_from_addr (as->map_list, addr);
354 if (map)
355 name = strdup (map->path);
356 #endif
357 if (!name)
358 /* End of ANDROID update. */
359 {
360 Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n",
361 (uint64_t) addr);
362 return 0;
363 }
364 }
365 else
366 name = (char*) dlname;
367
368 err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space, &segbase_bias);
369
370 if (!err)
371 {
372 fdesc = malloc (sizeof (struct unw_debug_frame_list));
373
374 fdesc->start = start;
375 fdesc->end = end;
376 fdesc->debug_frame = buf;
377 fdesc->debug_frame_size = bufsize;
378 fdesc->segbase_bias = segbase_bias;
379 fdesc->index = NULL;
380 fdesc->next = as->debug_frames;
381
382 as->debug_frames = fdesc;
383 }
384
385 /* ANDROID support update. */
386 if (name != dlname)
387 free(name);
388 /* End of ANDROID update. */
389
390 return fdesc;
391 }
392
393 struct debug_frame_tab
394 {
395 struct table_entry *tab;
396 uint32_t length;
397 uint32_t size;
398 };
399
400 static void
debug_frame_tab_append(struct debug_frame_tab * tab,unw_word_t fde_offset,unw_word_t start_ip)401 debug_frame_tab_append (struct debug_frame_tab *tab,
402 unw_word_t fde_offset, unw_word_t start_ip)
403 {
404 unsigned int length = tab->length;
405
406 if (length == tab->size)
407 {
408 tab->size *= 2;
409 tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
410 }
411
412 tab->tab[length].fde_offset = fde_offset;
413 tab->tab[length].start_ip_offset = start_ip;
414
415 tab->length = length + 1;
416 }
417
418 static void
debug_frame_tab_shrink(struct debug_frame_tab * tab)419 debug_frame_tab_shrink (struct debug_frame_tab *tab)
420 {
421 if (tab->size > tab->length)
422 {
423 tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length);
424 tab->size = tab->length;
425 }
426 }
427
428 static int
debug_frame_tab_compare(const void * a,const void * b)429 debug_frame_tab_compare (const void *a, const void *b)
430 {
431 const struct table_entry *fa = a, *fb = b;
432
433 if (fa->start_ip_offset > fb->start_ip_offset)
434 return 1;
435 else if (fa->start_ip_offset < fb->start_ip_offset)
436 return -1;
437 else
438 return 0;
439 }
440
441 PROTECTED int
dwarf_find_debug_frame(int found,unw_dyn_info_t * di_debug,unw_word_t ip,unw_word_t segbase,const char * obj_name,unw_word_t start,unw_word_t end)442 dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
443 unw_word_t segbase, const char* obj_name,
444 unw_word_t start, unw_word_t end)
445 {
446 unw_dyn_info_t *di;
447 struct unw_debug_frame_list *fdesc = 0;
448 unw_accessors_t *a;
449 unw_word_t addr;
450
451 Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
452 di = di_debug;
453
454 fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
455
456 if (!fdesc)
457 {
458 Debug (15, "couldn't load .debug_frame\n");
459 return found;
460 }
461 else
462 {
463 char *buf;
464 size_t bufsize;
465 unw_word_t item_start, item_end = 0;
466 uint32_t u32val = 0;
467 uint64_t cie_id = 0;
468 struct debug_frame_tab tab;
469
470 Debug (15, "loaded .debug_frame\n");
471
472 buf = fdesc->debug_frame;
473 bufsize = fdesc->debug_frame_size;
474
475 if (bufsize == 0)
476 {
477 Debug (15, "zero-length .debug_frame\n");
478 return found;
479 }
480
481 /* Now create a binary-search table, if it does not already exist. */
482 if (!fdesc->index)
483 {
484 addr = (unw_word_t) (uintptr_t) buf;
485
486 a = unw_get_accessors (unw_local_addr_space);
487
488 /* Find all FDE entries in debug_frame, and make into a sorted
489 index. */
490
491 tab.length = 0;
492 tab.size = 16;
493 tab.tab = calloc (tab.size, sizeof (struct table_entry));
494
495 while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
496 {
497 uint64_t id_for_cie;
498 item_start = addr;
499
500 dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
501
502 if (u32val == 0)
503 break;
504 else if (u32val != 0xffffffff)
505 {
506 uint32_t cie_id32 = 0;
507 item_end = addr + u32val;
508 dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
509 NULL);
510 cie_id = cie_id32;
511 id_for_cie = 0xffffffff;
512 }
513 else
514 {
515 uint64_t u64val = 0;
516 /* Extended length. */
517 dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
518 item_end = addr + u64val;
519
520 dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
521 id_for_cie = 0xffffffffffffffffull;
522 }
523
524 /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
525
526 if (cie_id == id_for_cie)
527 ;
528 /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
529 else
530 {
531 unw_word_t fde_addr = item_start;
532 unw_proc_info_t this_pi;
533 int err;
534
535 /*Debug (1, "Found FDE at %.8x\n", item_start);*/
536
537 err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
538 a, &fde_addr,
539 &this_pi, 0,
540 (uintptr_t) buf,
541 NULL);
542 if (err == 0)
543 {
544 Debug (15, "start_ip = %lx, end_ip = %lx\n",
545 (long) this_pi.start_ip, (long) this_pi.end_ip);
546 debug_frame_tab_append (&tab,
547 item_start - (unw_word_t) (uintptr_t) buf,
548 this_pi.start_ip);
549 }
550 /*else
551 Debug (1, "FDE parse failed\n");*/
552 }
553
554 addr = item_end;
555 }
556
557 debug_frame_tab_shrink (&tab);
558 qsort (tab.tab, tab.length, sizeof (struct table_entry),
559 debug_frame_tab_compare);
560 /* for (i = 0; i < tab.length; i++)
561 {
562 fprintf (stderr, "ip %x, fde offset %x\n",
563 (int) tab.tab[i].start_ip_offset,
564 (int) tab.tab[i].fde_offset);
565 }*/
566 fdesc->index = tab.tab;
567 fdesc->index_size = tab.length;
568 }
569
570 di->format = UNW_INFO_FORMAT_TABLE;
571 di->start_ip = fdesc->start;
572 di->end_ip = fdesc->end;
573 di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
574 di->u.ti.table_data = (unw_word_t *) fdesc;
575 di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
576 di->u.ti.segbase = segbase + fdesc->segbase_bias;
577
578 found = 1;
579 Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
580 "gp=0x%lx, table_data=0x%lx\n",
581 (char *) (uintptr_t) di->u.ti.name_ptr,
582 (long) di->u.ti.segbase, (long) di->u.ti.table_len,
583 (long) di->gp, (long) di->u.ti.table_data);
584 }
585 return found;
586 }
587
588 #endif /* CONFIG_DEBUG_FRAME */
589
590 #ifndef UNW_REMOTE_ONLY
591
592 /* ptr is a pointer to a dwarf_callback_data structure and, on entry,
593 member ip contains the instruction-pointer we're looking
594 for. */
595 HIDDEN int
dwarf_callback(struct dl_phdr_info * info,size_t size,void * ptr)596 dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
597 {
598 struct dwarf_callback_data *cb_data = ptr;
599 unw_dyn_info_t *di = &cb_data->di;
600 const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
601 unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
602 Elf_W(Addr) load_base, max_load_addr = 0;
603 int ret, need_unwind_info = cb_data->need_unwind_info;
604 unw_proc_info_t *pi = cb_data->pi;
605 struct dwarf_eh_frame_hdr *hdr;
606 unw_accessors_t *a;
607 long n;
608 int found = 0;
609 #ifdef CONFIG_DEBUG_FRAME
610 unw_word_t start, end;
611 #endif /* CONFIG_DEBUG_FRAME*/
612
613 ip = cb_data->ip;
614
615 /* Make sure struct dl_phdr_info is at least as big as we need. */
616 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
617 + sizeof (info->dlpi_phnum))
618 return -1;
619
620 Debug (15, "checking %s, base=0x%lx)\n",
621 info->dlpi_name, (long) info->dlpi_addr);
622
623 phdr = info->dlpi_phdr;
624 load_base = info->dlpi_addr;
625 p_text = NULL;
626 p_eh_hdr = NULL;
627 p_dynamic = NULL;
628
629 /* See if PC falls into one of the loaded segments. Find the
630 eh-header segment at the same time. */
631 for (n = info->dlpi_phnum; --n >= 0; phdr++)
632 {
633 if (phdr->p_type == PT_LOAD)
634 {
635 Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
636
637 if (ip >= vaddr && ip < vaddr + phdr->p_memsz)
638 p_text = phdr;
639
640 if (vaddr + phdr->p_filesz > max_load_addr)
641 max_load_addr = vaddr + phdr->p_filesz;
642 }
643 else if (phdr->p_type == PT_GNU_EH_FRAME)
644 p_eh_hdr = phdr;
645 else if (phdr->p_type == PT_DYNAMIC)
646 p_dynamic = phdr;
647 }
648
649 if (!p_text)
650 return 0;
651
652 if (p_eh_hdr)
653 {
654 if (p_dynamic)
655 {
656 /* For dynamicly linked executables and shared libraries,
657 DT_PLTGOT is the value that data-relative addresses are
658 relative to for that object. We call this the "gp". */
659 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
660 for (; dyn->d_tag != DT_NULL; ++dyn)
661 if (dyn->d_tag == DT_PLTGOT)
662 {
663 /* Assume that _DYNAMIC is writable and GLIBC has
664 relocated it (true for x86 at least). */
665 di->gp = dyn->d_un.d_ptr;
666 break;
667 }
668 }
669 else
670 /* Otherwise this is a static executable with no _DYNAMIC. Assume
671 that data-relative addresses are relative to 0, i.e.,
672 absolute. */
673 di->gp = 0;
674 pi->gp = di->gp;
675
676 hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
677 if (hdr->version != DW_EH_VERSION)
678 {
679 Debug (1, "table `%s' has unexpected version %d\n",
680 info->dlpi_name, hdr->version);
681 return 0;
682 }
683
684 a = unw_get_accessors (unw_local_addr_space);
685 addr = (unw_word_t) (uintptr_t) (hdr + 1);
686
687 /* (Optionally) read eh_frame_ptr: */
688 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
689 &addr, hdr->eh_frame_ptr_enc, pi,
690 &eh_frame_start, NULL)) < 0)
691 return ret;
692
693 /* (Optionally) read fde_count: */
694 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
695 &addr, hdr->fde_count_enc, pi,
696 &fde_count, NULL)) < 0)
697 return ret;
698
699 if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
700 {
701 /* If there is no search table or it has an unsupported
702 encoding, fall back on linear search. */
703 if (hdr->table_enc == DW_EH_PE_omit)
704 /* ANDROID support update. */
705 {
706 /* End of ANDROID update. */
707 Debug (4, "table `%s' lacks search table; doing linear search\n",
708 info->dlpi_name);
709 /* ANDROID support update. */
710 }
711 /* End of ANDROID update. */
712 else
713 /* ANDROID support update. */
714 {
715 /* End of ANDROID update. */
716 Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
717 info->dlpi_name, hdr->table_enc);
718 /* ANDROID support update. */
719 }
720 /* End of ANDROID update. */
721
722 eh_frame_end = max_load_addr; /* XXX can we do better? */
723
724 if (hdr->fde_count_enc == DW_EH_PE_omit)
725 fde_count = ~0UL;
726 if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
727 abort ();
728
729 /* XXX we know how to build a local binary search table for
730 .debug_frame, so we could do that here too. */
731 cb_data->single_fde = 1;
732 found = linear_search (unw_local_addr_space, ip,
733 eh_frame_start, eh_frame_end, fde_count,
734 pi, need_unwind_info, NULL);
735 if (found != 1)
736 found = 0;
737 }
738 else
739 {
740 di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
741 di->start_ip = p_text->p_vaddr + load_base;
742 di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
743 di->u.rti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
744 di->u.rti.table_data = addr;
745 assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0);
746 di->u.rti.table_len = (fde_count * sizeof (struct table_entry)
747 / sizeof (unw_word_t));
748 /* For the binary-search table in the eh_frame_hdr, data-relative
749 means relative to the start of that section... */
750 di->u.rti.segbase = (unw_word_t) (uintptr_t) hdr;
751
752 found = 1;
753 Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
754 "table_data=0x%lx\n", (char *) (uintptr_t) di->u.rti.name_ptr,
755 (long) di->u.rti.segbase, (long) di->u.rti.table_len,
756 (long) di->gp, (long) di->u.rti.table_data);
757 }
758 }
759
760 #ifdef CONFIG_DEBUG_FRAME
761 /* Find the start/end of the described region by parsing the phdr_info
762 structure. */
763 start = (unw_word_t) -1;
764 end = 0;
765
766 for (n = 0; n < info->dlpi_phnum; n++)
767 {
768 if (info->dlpi_phdr[n].p_type == PT_LOAD)
769 {
770 unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr;
771 unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz;
772
773 if (seg_start < start)
774 start = seg_start;
775
776 if (seg_end > end)
777 end = seg_end;
778 }
779 }
780
781 found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip,
782 info->dlpi_addr, info->dlpi_name, start,
783 end);
784 #endif /* CONFIG_DEBUG_FRAME */
785
786 return found;
787 }
788
789 HIDDEN int
dwarf_find_proc_info(unw_addr_space_t as,unw_word_t ip,unw_proc_info_t * pi,int need_unwind_info,void * arg)790 dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
791 unw_proc_info_t *pi, int need_unwind_info, void *arg)
792 {
793 struct dwarf_callback_data cb_data;
794 intrmask_t saved_mask;
795 int ret;
796
797 Debug (14, "looking for IP=0x%lx\n", (long) ip);
798
799 memset (&cb_data, 0, sizeof (cb_data));
800 cb_data.ip = ip;
801 cb_data.pi = pi;
802 cb_data.need_unwind_info = need_unwind_info;
803 cb_data.di.format = -1;
804 cb_data.di_debug.format = -1;
805
806 SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
807 ret = dl_iterate_phdr (dwarf_callback, &cb_data);
808 SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
809
810 if (ret <= 0)
811 {
812 Debug (14, "IP=0x%lx not found\n", (long) ip);
813 return -UNW_ENOINFO;
814 }
815
816 if (cb_data.single_fde)
817 /* already got the result in *pi */
818 return 0;
819
820 /* search the table: */
821 if (cb_data.di.format != -1)
822 ret = dwarf_search_unwind_table (as, ip, &cb_data.di,
823 pi, need_unwind_info, arg);
824 else
825 ret = -UNW_ENOINFO;
826
827 if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
828 ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi,
829 need_unwind_info, arg);
830 return ret;
831 }
832
833 static inline const struct table_entry *
lookup(const struct table_entry * table,size_t table_size,int32_t rel_ip)834 lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip)
835 {
836 unsigned long table_len = table_size / sizeof (struct table_entry);
837 const struct table_entry *e = NULL;
838 unsigned long lo, hi, mid;
839
840 /* do a binary search for right entry: */
841 for (lo = 0, hi = table_len; lo < hi;)
842 {
843 mid = (lo + hi) / 2;
844 e = table + mid;
845 Debug (15, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset);
846 if (rel_ip < e->start_ip_offset)
847 hi = mid;
848 else
849 lo = mid + 1;
850 }
851 if (hi <= 0)
852 return NULL;
853 e = table + hi - 1;
854 return e;
855 }
856
857 #endif /* !UNW_REMOTE_ONLY */
858
859 #ifndef UNW_LOCAL_ONLY
860
861 /* Lookup an unwind-table entry in remote memory. Returns 1 if an
862 entry is found, 0 if no entry is found, negative if an error
863 occurred reading remote memory. */
864 static int
remote_lookup(unw_addr_space_t as,unw_word_t table,size_t table_size,int32_t rel_ip,struct table_entry * e,void * arg)865 remote_lookup (unw_addr_space_t as,
866 unw_word_t table, size_t table_size, int32_t rel_ip,
867 struct table_entry *e, void *arg)
868 {
869 unsigned long table_len = table_size / sizeof (struct table_entry);
870 unw_accessors_t *a = unw_get_accessors (as);
871 unsigned long lo, hi, mid;
872 unw_word_t e_addr = 0;
873 int32_t start;
874 int ret;
875
876 /* do a binary search for right entry: */
877 for (lo = 0, hi = table_len; lo < hi;)
878 {
879 mid = (lo + hi) / 2;
880 e_addr = table + mid * sizeof (struct table_entry);
881 if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0)
882 return ret;
883
884 if (rel_ip < start)
885 hi = mid;
886 else
887 lo = mid + 1;
888 }
889 if (hi <= 0)
890 return 0;
891 e_addr = table + (hi - 1) * sizeof (struct table_entry);
892 if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0
893 || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0)
894 return ret;
895 return 1;
896 }
897
898 #endif /* !UNW_LOCAL_ONLY */
899
900 PROTECTED int
dwarf_search_unwind_table(unw_addr_space_t as,unw_word_t ip,unw_dyn_info_t * di,unw_proc_info_t * pi,int need_unwind_info,void * arg)901 dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
902 unw_dyn_info_t *di, unw_proc_info_t *pi,
903 int need_unwind_info, void *arg)
904 {
905 const struct table_entry *e = NULL, *table;
906 unw_word_t segbase = 0, fde_addr;
907 unw_accessors_t *a;
908 #ifndef UNW_LOCAL_ONLY
909 struct table_entry ent;
910 #endif
911 int ret;
912 unw_word_t debug_frame_base;
913 size_t table_len;
914
915 #ifdef UNW_REMOTE_ONLY
916 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE);
917 #else
918 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
919 || di->format == UNW_INFO_FORMAT_TABLE);
920 #endif
921 assert (ip >= di->start_ip && ip < di->end_ip);
922
923 if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
924 {
925 table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
926 table_len = di->u.rti.table_len * sizeof (unw_word_t);
927 debug_frame_base = 0;
928 }
929 else
930 {
931 #ifndef UNW_REMOTE_ONLY
932 struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
933
934 /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
935 space. Both the index and the unwind tables live in local memory, but
936 the address space to check for properties like the address size and
937 endianness is the target one. */
938 as = unw_local_addr_space;
939 table = fdesc->index;
940 table_len = fdesc->index_size * sizeof (struct table_entry);
941 debug_frame_base = (uintptr_t) fdesc->debug_frame;
942 #endif
943 }
944
945 a = unw_get_accessors (as);
946
947 #ifndef UNW_REMOTE_ONLY
948 if (as == unw_local_addr_space)
949 {
950 segbase = di->u.rti.segbase;
951 e = lookup (table, table_len, ip - segbase);
952 }
953 else
954 #endif
955 {
956 #ifndef UNW_LOCAL_ONLY
957 segbase = di->u.rti.segbase;
958 if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
959 ip - segbase, &ent, arg)) < 0)
960 return ret;
961 if (ret)
962 e = &ent;
963 else
964 e = NULL; /* no info found */
965 #endif
966 }
967 if (!e)
968 {
969 Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n",
970 (long) ip, (long) di->start_ip, (long) di->end_ip);
971 /* IP is inside this table's range, but there is no explicit
972 unwind info. */
973 return -UNW_ENOINFO;
974 }
975 Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
976 (long) ip, (long) (e->start_ip_offset));
977 if (debug_frame_base)
978 fde_addr = e->fde_offset + debug_frame_base;
979 else
980 fde_addr = e->fde_offset + segbase;
981 Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, "
982 "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
983 (long) debug_frame_base, (long) fde_addr);
984 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
985 need_unwind_info,
986 debug_frame_base, arg)) < 0)
987 return ret;
988
989 /* .debug_frame uses an absolute encoding that does not know about any
990 shared library relocation. */
991 if (di->format == UNW_INFO_FORMAT_TABLE)
992 {
993 pi->start_ip += segbase;
994 pi->end_ip += segbase;
995 pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
996 }
997
998 if (ip < pi->start_ip || ip >= pi->end_ip)
999 {
1000 /* ANDROID support update. */
1001 if (need_unwind_info && pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE)
1002 {
1003 /* Free the memory used if the call fails. Otherwise, when there
1004 * is a mix of dwarf and other unwind data, the memory allocated
1005 * will be leaked.
1006 */
1007 mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
1008 pi->unwind_info = NULL;
1009 }
1010 /* End of ANDROID support update. */
1011 return -UNW_ENOINFO;
1012 }
1013
1014 return 0;
1015 }
1016
1017 HIDDEN void
dwarf_put_unwind_info(unw_addr_space_t as,unw_proc_info_t * pi,void * arg)1018 dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
1019 {
1020 return; /* always a nop */
1021 }
1022