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)94 load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
95 {
96 FILE *f;
97 Elf_W (Ehdr) ehdr;
98 Elf_W (Half) shstrndx;
99 Elf_W (Shdr) *sec_hdrs = NULL;
100 char *stringtab = NULL;
101 unsigned int i;
102 size_t linksize = 0;
103 char *linkbuf = NULL;
104
105 *buf = NULL;
106 *bufsize = 0;
107
108 f = fopen (file, "r");
109
110 if (!f)
111 return 1;
112
113 if (fread (&ehdr, sizeof (Elf_W (Ehdr)), 1, f) != 1)
114 goto file_error;
115
116 shstrndx = ehdr.e_shstrndx;
117
118 Debug (4, "opened file '%s'. Section header at offset %d\n",
119 file, (int) ehdr.e_shoff);
120
121 fseek (f, ehdr.e_shoff, SEEK_SET);
122 sec_hdrs = calloc (ehdr.e_shnum, sizeof (Elf_W (Shdr)));
123 if (fread (sec_hdrs, sizeof (Elf_W (Shdr)), ehdr.e_shnum, f) != ehdr.e_shnum)
124 goto file_error;
125
126 Debug (4, "loading string table of size %ld\n",
127 (long) sec_hdrs[shstrndx].sh_size);
128 stringtab = malloc (sec_hdrs[shstrndx].sh_size);
129 fseek (f, sec_hdrs[shstrndx].sh_offset, SEEK_SET);
130 if (fread (stringtab, 1, sec_hdrs[shstrndx].sh_size, f) != sec_hdrs[shstrndx].sh_size)
131 goto file_error;
132
133 for (i = 1; i < ehdr.e_shnum && *buf == NULL; i++)
134 {
135 char *secname = &stringtab[sec_hdrs[i].sh_name];
136
137 if (strcmp (secname, ".debug_frame") == 0)
138 {
139 *bufsize = sec_hdrs[i].sh_size;
140 *buf = malloc (*bufsize);
141
142 fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
143 if (fread (*buf, 1, *bufsize, f) != *bufsize)
144 goto file_error;
145
146 Debug (4, "read %zd bytes of .debug_frame from offset %ld\n",
147 *bufsize, (long) sec_hdrs[i].sh_offset);
148 }
149 else if (strcmp (secname, ".gnu_debuglink") == 0)
150 {
151 linksize = sec_hdrs[i].sh_size;
152 linkbuf = malloc (linksize);
153
154 fseek (f, sec_hdrs[i].sh_offset, SEEK_SET);
155 if (fread (linkbuf, 1, linksize, f) != linksize)
156 goto file_error;
157
158 Debug (4, "read %zd bytes of .gnu_debuglink from offset %ld\n",
159 linksize, (long) sec_hdrs[i].sh_offset);
160 }
161 }
162
163 free (stringtab);
164 free (sec_hdrs);
165
166 fclose (f);
167
168 /* Ignore separate debug files which contain a .gnu_debuglink section. */
169 if (linkbuf && is_local == -1)
170 {
171 free (linkbuf);
172 return 1;
173 }
174
175 if (*buf == NULL && linkbuf != NULL && memchr (linkbuf, 0, linksize) != NULL)
176 {
177 char *newname, *basedir, *p;
178 static const char *debugdir = "/usr/lib/debug";
179 int ret;
180
181 /* XXX: Don't bother with the checksum; just search for the file. */
182 basedir = malloc (strlen (file) + 1);
183 newname = malloc (strlen (linkbuf) + strlen (debugdir)
184 + strlen (file) + 9);
185
186 p = strrchr (file, '/');
187 if (p != NULL)
188 {
189 memcpy (basedir, file, p - file);
190 basedir[p - file] = '\0';
191 }
192 else
193 basedir[0] = 0;
194
195 strcpy (newname, basedir);
196 strcat (newname, "/");
197 strcat (newname, linkbuf);
198 ret = load_debug_frame (newname, buf, bufsize, -1);
199
200 if (ret == 1)
201 {
202 strcpy (newname, basedir);
203 strcat (newname, "/.debug/");
204 strcat (newname, linkbuf);
205 ret = load_debug_frame (newname, buf, bufsize, -1);
206 }
207
208 if (ret == 1 && is_local == 1)
209 {
210 strcpy (newname, debugdir);
211 strcat (newname, basedir);
212 strcat (newname, "/");
213 strcat (newname, linkbuf);
214 ret = load_debug_frame (newname, buf, bufsize, -1);
215 }
216
217 free (basedir);
218 free (newname);
219 }
220 free (linkbuf);
221
222 return 0;
223
224 /* An error reading image file. Release resources and return error code */
225 file_error:
226 free(stringtab);
227 free(sec_hdrs);
228 free(linkbuf);
229 free(*buf);
230 fclose(f);
231
232 return 1;
233 }
234
235 /* Locate the binary which originated the contents of address ADDR. Return
236 the name of the binary in *name (space is allocated by the caller)
237 Returns 0 if a binary is successfully found, or 1 if an error occurs. */
238
239 /* ANDROID support update. */
240 /* Removed the find_binary_for_address function. */
241 /* End of ANDROID update. */
242
243 /* Locate and/or try to load a debug_frame section for address ADDR. Return
244 pointer to debug frame descriptor, or zero if not found. */
245
246 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)247 locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
248 unw_word_t start, unw_word_t end)
249 {
250 struct unw_debug_frame_list *w, *fdesc = 0;
251 int err;
252 char *buf;
253 size_t bufsize;
254 /* ANDROID support update. */
255 char *name = NULL;
256 /* End of ANDROID update. */
257
258 /* First, see if we loaded this frame already. */
259
260 for (w = as->debug_frames; w; w = w->next)
261 {
262 Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end);
263 if (addr >= w->start && addr < w->end)
264 return w;
265 }
266
267 /* ANDROID support update. */
268 /* If the object name we receive is blank, there's still a chance of locating
269 the file by looking at the maps cache. */
270
271 if (strcmp (dlname, "") == 0)
272 {
273 #ifdef UNW_LOCAL_ONLY
274 name = map_local_get_image_name (addr);
275 #else
276 struct map_info *map = map_find_from_addr (as->map_list, addr);
277 if (map)
278 name = strdup (map->path);
279 #endif
280 if (!name)
281 /* End of ANDROID update. */
282 {
283 Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n",
284 (uint64_t) addr);
285 return 0;
286 }
287 }
288 else
289 name = (char*) dlname;
290
291 err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
292
293 if (!err)
294 {
295 fdesc = malloc (sizeof (struct unw_debug_frame_list));
296
297 fdesc->start = start;
298 fdesc->end = end;
299 fdesc->debug_frame = buf;
300 fdesc->debug_frame_size = bufsize;
301 fdesc->index = NULL;
302 fdesc->next = as->debug_frames;
303
304 as->debug_frames = fdesc;
305 }
306
307 /* ANDROID support update. */
308 if (name != dlname)
309 free(name);
310 /* End of ANDROID update. */
311
312 return fdesc;
313 }
314
315 struct debug_frame_tab
316 {
317 struct table_entry *tab;
318 uint32_t length;
319 uint32_t size;
320 };
321
322 static void
debug_frame_tab_append(struct debug_frame_tab * tab,unw_word_t fde_offset,unw_word_t start_ip)323 debug_frame_tab_append (struct debug_frame_tab *tab,
324 unw_word_t fde_offset, unw_word_t start_ip)
325 {
326 unsigned int length = tab->length;
327
328 if (length == tab->size)
329 {
330 tab->size *= 2;
331 tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
332 }
333
334 tab->tab[length].fde_offset = fde_offset;
335 tab->tab[length].start_ip_offset = start_ip;
336
337 tab->length = length + 1;
338 }
339
340 static void
debug_frame_tab_shrink(struct debug_frame_tab * tab)341 debug_frame_tab_shrink (struct debug_frame_tab *tab)
342 {
343 if (tab->size > tab->length)
344 {
345 tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->length);
346 tab->size = tab->length;
347 }
348 }
349
350 static int
debug_frame_tab_compare(const void * a,const void * b)351 debug_frame_tab_compare (const void *a, const void *b)
352 {
353 const struct table_entry *fa = a, *fb = b;
354
355 if (fa->start_ip_offset > fb->start_ip_offset)
356 return 1;
357 else if (fa->start_ip_offset < fb->start_ip_offset)
358 return -1;
359 else
360 return 0;
361 }
362
363 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)364 dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
365 unw_word_t segbase, const char* obj_name,
366 unw_word_t start, unw_word_t end)
367 {
368 unw_dyn_info_t *di;
369 struct unw_debug_frame_list *fdesc = 0;
370 unw_accessors_t *a;
371 unw_word_t addr;
372
373 Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
374 di = di_debug;
375
376 fdesc = locate_debug_info (unw_local_addr_space, ip, obj_name, start, end);
377
378 if (!fdesc)
379 {
380 Debug (15, "couldn't load .debug_frame\n");
381 return found;
382 }
383 else
384 {
385 char *buf;
386 size_t bufsize;
387 unw_word_t item_start, item_end = 0;
388 uint32_t u32val = 0;
389 uint64_t cie_id = 0;
390 struct debug_frame_tab tab;
391
392 Debug (15, "loaded .debug_frame\n");
393
394 buf = fdesc->debug_frame;
395 bufsize = fdesc->debug_frame_size;
396
397 if (bufsize == 0)
398 {
399 Debug (15, "zero-length .debug_frame\n");
400 return found;
401 }
402
403 /* Now create a binary-search table, if it does not already exist. */
404 if (!fdesc->index)
405 {
406 addr = (unw_word_t) (uintptr_t) buf;
407
408 a = unw_get_accessors (unw_local_addr_space);
409
410 /* Find all FDE entries in debug_frame, and make into a sorted
411 index. */
412
413 tab.length = 0;
414 tab.size = 16;
415 tab.tab = calloc (tab.size, sizeof (struct table_entry));
416
417 while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
418 {
419 uint64_t id_for_cie;
420 item_start = addr;
421
422 dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
423
424 if (u32val == 0)
425 break;
426 else if (u32val != 0xffffffff)
427 {
428 uint32_t cie_id32 = 0;
429 item_end = addr + u32val;
430 dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32,
431 NULL);
432 cie_id = cie_id32;
433 id_for_cie = 0xffffffff;
434 }
435 else
436 {
437 uint64_t u64val = 0;
438 /* Extended length. */
439 dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
440 item_end = addr + u64val;
441
442 dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
443 id_for_cie = 0xffffffffffffffffull;
444 }
445
446 /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
447
448 if (cie_id == id_for_cie)
449 ;
450 /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
451 else
452 {
453 unw_word_t fde_addr = item_start;
454 unw_proc_info_t this_pi;
455 int err;
456
457 /*Debug (1, "Found FDE at %.8x\n", item_start);*/
458
459 err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
460 a, &fde_addr,
461 &this_pi, 0,
462 (uintptr_t) buf,
463 NULL);
464 if (err == 0)
465 {
466 Debug (15, "start_ip = %lx, end_ip = %lx\n",
467 (long) this_pi.start_ip, (long) this_pi.end_ip);
468 debug_frame_tab_append (&tab,
469 item_start - (unw_word_t) (uintptr_t) buf,
470 this_pi.start_ip);
471 }
472 /*else
473 Debug (1, "FDE parse failed\n");*/
474 }
475
476 addr = item_end;
477 }
478
479 debug_frame_tab_shrink (&tab);
480 qsort (tab.tab, tab.length, sizeof (struct table_entry),
481 debug_frame_tab_compare);
482 /* for (i = 0; i < tab.length; i++)
483 {
484 fprintf (stderr, "ip %x, fde offset %x\n",
485 (int) tab.tab[i].start_ip_offset,
486 (int) tab.tab[i].fde_offset);
487 }*/
488 fdesc->index = tab.tab;
489 fdesc->index_size = tab.length;
490 }
491
492 di->format = UNW_INFO_FORMAT_TABLE;
493 di->start_ip = fdesc->start;
494 di->end_ip = fdesc->end;
495 di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
496 di->u.ti.table_data = (unw_word_t *) fdesc;
497 di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
498 di->u.ti.segbase = segbase;
499
500 found = 1;
501 Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
502 "gp=0x%lx, table_data=0x%lx\n",
503 (char *) (uintptr_t) di->u.ti.name_ptr,
504 (long) di->u.ti.segbase, (long) di->u.ti.table_len,
505 (long) di->gp, (long) di->u.ti.table_data);
506 }
507 return found;
508 }
509
510 #endif /* CONFIG_DEBUG_FRAME */
511
512 #ifndef UNW_REMOTE_ONLY
513
514 /* ptr is a pointer to a dwarf_callback_data structure and, on entry,
515 member ip contains the instruction-pointer we're looking
516 for. */
517 HIDDEN int
dwarf_callback(struct dl_phdr_info * info,size_t size,void * ptr)518 dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
519 {
520 struct dwarf_callback_data *cb_data = ptr;
521 unw_dyn_info_t *di = &cb_data->di;
522 const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
523 unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
524 Elf_W(Addr) load_base, max_load_addr = 0;
525 int ret, need_unwind_info = cb_data->need_unwind_info;
526 unw_proc_info_t *pi = cb_data->pi;
527 struct dwarf_eh_frame_hdr *hdr;
528 unw_accessors_t *a;
529 long n;
530 int found = 0;
531 #ifdef CONFIG_DEBUG_FRAME
532 unw_word_t start, end;
533 #endif /* CONFIG_DEBUG_FRAME*/
534
535 ip = cb_data->ip;
536
537 /* Make sure struct dl_phdr_info is at least as big as we need. */
538 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
539 + sizeof (info->dlpi_phnum))
540 return -1;
541
542 Debug (15, "checking %s, base=0x%lx)\n",
543 info->dlpi_name, (long) info->dlpi_addr);
544
545 phdr = info->dlpi_phdr;
546 load_base = info->dlpi_addr;
547 p_text = NULL;
548 p_eh_hdr = NULL;
549 p_dynamic = NULL;
550
551 /* See if PC falls into one of the loaded segments. Find the
552 eh-header segment at the same time. */
553 for (n = info->dlpi_phnum; --n >= 0; phdr++)
554 {
555 if (phdr->p_type == PT_LOAD)
556 {
557 Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
558
559 if (ip >= vaddr && ip < vaddr + phdr->p_memsz)
560 p_text = phdr;
561
562 if (vaddr + phdr->p_filesz > max_load_addr)
563 max_load_addr = vaddr + phdr->p_filesz;
564 }
565 else if (phdr->p_type == PT_GNU_EH_FRAME)
566 p_eh_hdr = phdr;
567 else if (phdr->p_type == PT_DYNAMIC)
568 p_dynamic = phdr;
569 }
570
571 if (!p_text)
572 return 0;
573
574 if (p_eh_hdr)
575 {
576 if (p_dynamic)
577 {
578 /* For dynamicly linked executables and shared libraries,
579 DT_PLTGOT is the value that data-relative addresses are
580 relative to for that object. We call this the "gp". */
581 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
582 for (; dyn->d_tag != DT_NULL; ++dyn)
583 if (dyn->d_tag == DT_PLTGOT)
584 {
585 /* Assume that _DYNAMIC is writable and GLIBC has
586 relocated it (true for x86 at least). */
587 di->gp = dyn->d_un.d_ptr;
588 break;
589 }
590 }
591 else
592 /* Otherwise this is a static executable with no _DYNAMIC. Assume
593 that data-relative addresses are relative to 0, i.e.,
594 absolute. */
595 di->gp = 0;
596 pi->gp = di->gp;
597
598 hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
599 if (hdr->version != DW_EH_VERSION)
600 {
601 Debug (1, "table `%s' has unexpected version %d\n",
602 info->dlpi_name, hdr->version);
603 return 0;
604 }
605
606 a = unw_get_accessors (unw_local_addr_space);
607 addr = (unw_word_t) (uintptr_t) (hdr + 1);
608
609 /* (Optionally) read eh_frame_ptr: */
610 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
611 &addr, hdr->eh_frame_ptr_enc, pi,
612 &eh_frame_start, NULL)) < 0)
613 return ret;
614
615 /* (Optionally) read fde_count: */
616 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
617 &addr, hdr->fde_count_enc, pi,
618 &fde_count, NULL)) < 0)
619 return ret;
620
621 if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
622 {
623 /* If there is no search table or it has an unsupported
624 encoding, fall back on linear search. */
625 if (hdr->table_enc == DW_EH_PE_omit)
626 /* ANDROID support update. */
627 {
628 /* End of ANDROID update. */
629 Debug (4, "table `%s' lacks search table; doing linear search\n",
630 info->dlpi_name);
631 /* ANDROID support update. */
632 }
633 /* End of ANDROID update. */
634 else
635 /* ANDROID support update. */
636 {
637 /* End of ANDROID update. */
638 Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
639 info->dlpi_name, hdr->table_enc);
640 /* ANDROID support update. */
641 }
642 /* End of ANDROID update. */
643
644 eh_frame_end = max_load_addr; /* XXX can we do better? */
645
646 if (hdr->fde_count_enc == DW_EH_PE_omit)
647 fde_count = ~0UL;
648 if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
649 abort ();
650
651 /* XXX we know how to build a local binary search table for
652 .debug_frame, so we could do that here too. */
653 cb_data->single_fde = 1;
654 found = linear_search (unw_local_addr_space, ip,
655 eh_frame_start, eh_frame_end, fde_count,
656 pi, need_unwind_info, NULL);
657 if (found != 1)
658 found = 0;
659 }
660 else
661 {
662 di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
663 di->start_ip = p_text->p_vaddr + load_base;
664 di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
665 di->u.rti.name_ptr = (unw_word_t) (uintptr_t) info->dlpi_name;
666 di->u.rti.table_data = addr;
667 assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0);
668 di->u.rti.table_len = (fde_count * sizeof (struct table_entry)
669 / sizeof (unw_word_t));
670 /* For the binary-search table in the eh_frame_hdr, data-relative
671 means relative to the start of that section... */
672 di->u.rti.segbase = (unw_word_t) (uintptr_t) hdr;
673
674 found = 1;
675 Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
676 "table_data=0x%lx\n", (char *) (uintptr_t) di->u.rti.name_ptr,
677 (long) di->u.rti.segbase, (long) di->u.rti.table_len,
678 (long) di->gp, (long) di->u.rti.table_data);
679 }
680 }
681
682 #ifdef CONFIG_DEBUG_FRAME
683 /* Find the start/end of the described region by parsing the phdr_info
684 structure. */
685 start = (unw_word_t) -1;
686 end = 0;
687
688 for (n = 0; n < info->dlpi_phnum; n++)
689 {
690 if (info->dlpi_phdr[n].p_type == PT_LOAD)
691 {
692 unw_word_t seg_start = info->dlpi_addr + info->dlpi_phdr[n].p_vaddr;
693 unw_word_t seg_end = seg_start + info->dlpi_phdr[n].p_memsz;
694
695 if (seg_start < start)
696 start = seg_start;
697
698 if (seg_end > end)
699 end = seg_end;
700 }
701 }
702
703 found = dwarf_find_debug_frame (found, &cb_data->di_debug, ip,
704 info->dlpi_addr, info->dlpi_name, start,
705 end);
706 #endif /* CONFIG_DEBUG_FRAME */
707
708 return found;
709 }
710
711 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)712 dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
713 unw_proc_info_t *pi, int need_unwind_info, void *arg)
714 {
715 struct dwarf_callback_data cb_data;
716 intrmask_t saved_mask;
717 int ret;
718
719 Debug (14, "looking for IP=0x%lx\n", (long) ip);
720
721 memset (&cb_data, 0, sizeof (cb_data));
722 cb_data.ip = ip;
723 cb_data.pi = pi;
724 cb_data.need_unwind_info = need_unwind_info;
725 cb_data.di.format = -1;
726 cb_data.di_debug.format = -1;
727
728 SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
729 ret = dl_iterate_phdr (dwarf_callback, &cb_data);
730 SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
731
732 if (ret <= 0)
733 {
734 Debug (14, "IP=0x%lx not found\n", (long) ip);
735 return -UNW_ENOINFO;
736 }
737
738 if (cb_data.single_fde)
739 /* already got the result in *pi */
740 return 0;
741
742 /* search the table: */
743 if (cb_data.di.format != -1)
744 ret = dwarf_search_unwind_table (as, ip, &cb_data.di,
745 pi, need_unwind_info, arg);
746 else
747 ret = -UNW_ENOINFO;
748
749 if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
750 ret = dwarf_search_unwind_table (as, ip, &cb_data.di_debug, pi,
751 need_unwind_info, arg);
752 return ret;
753 }
754
755 static inline const struct table_entry *
lookup(const struct table_entry * table,size_t table_size,int32_t rel_ip)756 lookup (const struct table_entry *table, size_t table_size, int32_t rel_ip)
757 {
758 unsigned long table_len = table_size / sizeof (struct table_entry);
759 const struct table_entry *e = NULL;
760 unsigned long lo, hi, mid;
761
762 /* do a binary search for right entry: */
763 for (lo = 0, hi = table_len; lo < hi;)
764 {
765 mid = (lo + hi) / 2;
766 e = table + mid;
767 Debug (15, "e->start_ip_offset = %lx\n", (long) e->start_ip_offset);
768 if (rel_ip < e->start_ip_offset)
769 hi = mid;
770 else
771 lo = mid + 1;
772 }
773 if (hi <= 0)
774 return NULL;
775 e = table + hi - 1;
776 return e;
777 }
778
779 #endif /* !UNW_REMOTE_ONLY */
780
781 #ifndef UNW_LOCAL_ONLY
782
783 /* Lookup an unwind-table entry in remote memory. Returns 1 if an
784 entry is found, 0 if no entry is found, negative if an error
785 occurred reading remote memory. */
786 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)787 remote_lookup (unw_addr_space_t as,
788 unw_word_t table, size_t table_size, int32_t rel_ip,
789 struct table_entry *e, void *arg)
790 {
791 unsigned long table_len = table_size / sizeof (struct table_entry);
792 unw_accessors_t *a = unw_get_accessors (as);
793 unsigned long lo, hi, mid;
794 unw_word_t e_addr = 0;
795 int32_t start;
796 int ret;
797
798 /* do a binary search for right entry: */
799 for (lo = 0, hi = table_len; lo < hi;)
800 {
801 mid = (lo + hi) / 2;
802 e_addr = table + mid * sizeof (struct table_entry);
803 if ((ret = dwarf_reads32 (as, a, &e_addr, &start, arg)) < 0)
804 return ret;
805
806 if (rel_ip < start)
807 hi = mid;
808 else
809 lo = mid + 1;
810 }
811 if (hi <= 0)
812 return 0;
813 e_addr = table + (hi - 1) * sizeof (struct table_entry);
814 if ((ret = dwarf_reads32 (as, a, &e_addr, &e->start_ip_offset, arg)) < 0
815 || (ret = dwarf_reads32 (as, a, &e_addr, &e->fde_offset, arg)) < 0)
816 return ret;
817 return 1;
818 }
819
820 #endif /* !UNW_LOCAL_ONLY */
821
822 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)823 dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
824 unw_dyn_info_t *di, unw_proc_info_t *pi,
825 int need_unwind_info, void *arg)
826 {
827 const struct table_entry *e = NULL, *table;
828 unw_word_t segbase = 0, fde_addr;
829 unw_accessors_t *a;
830 #ifndef UNW_LOCAL_ONLY
831 struct table_entry ent;
832 #endif
833 int ret;
834 unw_word_t debug_frame_base;
835 size_t table_len;
836
837 #ifdef UNW_REMOTE_ONLY
838 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE);
839 #else
840 assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
841 || di->format == UNW_INFO_FORMAT_TABLE);
842 #endif
843 assert (ip >= di->start_ip && ip < di->end_ip);
844
845 if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
846 {
847 table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
848 table_len = di->u.rti.table_len * sizeof (unw_word_t);
849 debug_frame_base = 0;
850 }
851 else
852 {
853 #ifndef UNW_REMOTE_ONLY
854 struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
855
856 /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
857 space. Both the index and the unwind tables live in local memory, but
858 the address space to check for properties like the address size and
859 endianness is the target one. */
860 as = unw_local_addr_space;
861 table = fdesc->index;
862 table_len = fdesc->index_size * sizeof (struct table_entry);
863 debug_frame_base = (uintptr_t) fdesc->debug_frame;
864 #endif
865 }
866
867 a = unw_get_accessors (as);
868
869 #ifndef UNW_REMOTE_ONLY
870 if (as == unw_local_addr_space)
871 {
872 segbase = di->u.rti.segbase;
873 e = lookup (table, table_len, ip - segbase);
874 }
875 else
876 #endif
877 {
878 #ifndef UNW_LOCAL_ONLY
879 segbase = di->u.rti.segbase;
880 if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
881 ip - segbase, &ent, arg)) < 0)
882 return ret;
883 if (ret)
884 e = &ent;
885 else
886 e = NULL; /* no info found */
887 #endif
888 }
889 if (!e)
890 {
891 Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n",
892 (long) ip, (long) di->start_ip, (long) di->end_ip);
893 /* IP is inside this table's range, but there is no explicit
894 unwind info. */
895 return -UNW_ENOINFO;
896 }
897 Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
898 (long) ip, (long) (e->start_ip_offset));
899 if (debug_frame_base)
900 fde_addr = e->fde_offset + debug_frame_base;
901 else
902 fde_addr = e->fde_offset + segbase;
903 Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, "
904 "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
905 (long) debug_frame_base, (long) fde_addr);
906 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
907 need_unwind_info,
908 debug_frame_base, arg)) < 0)
909 return ret;
910
911 /* .debug_frame uses an absolute encoding that does not know about any
912 shared library relocation. */
913 if (di->format == UNW_INFO_FORMAT_TABLE)
914 {
915 pi->start_ip += segbase;
916 pi->end_ip += segbase;
917 pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
918 }
919
920 if (ip < pi->start_ip || ip >= pi->end_ip)
921 {
922 /* ANDROID support update. */
923 if (need_unwind_info && pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE)
924 {
925 /* Free the memory used if the call fails. Otherwise, when there
926 * is a mix of dwarf and other unwind data, the memory allocated
927 * will be leaked.
928 */
929 mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
930 pi->unwind_info = NULL;
931 }
932 /* End of ANDROID support update. */
933 return -UNW_ENOINFO;
934 }
935
936 return 0;
937 }
938
939 HIDDEN void
dwarf_put_unwind_info(unw_addr_space_t as,unw_proc_info_t * pi,void * arg)940 dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
941 {
942 return; /* always a nop */
943 }
944