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