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 #ifdef HAVE_ZLIB
38 #include <zlib.h>
39 #endif /* HAVE_ZLIB */
40
41 struct table_entry
42 {
43 int32_t start_ip_offset;
44 int32_t fde_offset;
45 };
46
47 #ifndef UNW_REMOTE_ONLY
48
49 #ifdef __linux__
50 #include "os-linux.h"
51 #endif
52
53 #ifndef __clang__
54 static ALIAS(dwarf_search_unwind_table) int
55 dwarf_search_unwind_table_int (unw_addr_space_t as,
56 unw_word_t ip,
57 unw_dyn_info_t *di,
58 unw_proc_info_t *pi,
59 int need_unwind_info, void *arg);
60 #else
61 #define dwarf_search_unwind_table_int dwarf_search_unwind_table
62 #endif
63
64 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)65 linear_search (unw_addr_space_t as, unw_word_t ip,
66 unw_word_t eh_frame_start, unw_word_t eh_frame_end,
67 unw_word_t fde_count,
68 unw_proc_info_t *pi, int need_unwind_info, void *arg)
69 {
70 unw_accessors_t *a = unw_get_accessors_int (unw_local_addr_space);
71 unw_word_t i = 0, fde_addr, addr = eh_frame_start;
72 int ret;
73
74 while (i++ < fde_count && addr < eh_frame_end)
75 {
76 fde_addr = addr;
77 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
78 eh_frame_start,
79 0, 0, arg)) < 0)
80 return ret;
81
82 if (ip >= pi->start_ip && ip < pi->end_ip)
83 {
84 if (!need_unwind_info)
85 return 1;
86 addr = fde_addr;
87 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
88 eh_frame_start,
89 need_unwind_info, 0,
90 arg))
91 < 0)
92 return ret;
93 return 1;
94 }
95 }
96 return -UNW_ENOINFO;
97 }
98 #endif /* !UNW_REMOTE_ONLY */
99
100 #ifdef CONFIG_DEBUG_FRAME
101 /* Load .debug_frame section from FILE. Allocates and returns space
102 in *BUF, and sets *BUFSIZE to its size. IS_LOCAL is 1 if using the
103 local process, in which case we can search the system debug file
104 directory; 0 for other address spaces, in which case we do
105 not. Returns 0 on success, 1 on error. Succeeds even if the file
106 contains no .debug_frame. */
107 /* XXX: Could use mmap; but elf_map_image keeps tons mapped in. */
108
109 static int
load_debug_frame(const char * file,char ** buf,size_t * bufsize,int is_local,unw_word_t segbase,unw_word_t * load_offset)110 load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local,
111 unw_word_t segbase, unw_word_t *load_offset)
112 {
113 struct elf_image ei;
114 Elf_W (Ehdr) *ehdr;
115 Elf_W (Phdr) *phdr;
116 Elf_W (Shdr) *shdr;
117 int i;
118 int ret;
119
120 ei.image = NULL;
121 *load_offset = 0;
122
123 ret = elf_w (load_debuglink) (file, &ei, is_local);
124 if (ret != 0)
125 return ret;
126
127 shdr = elf_w (find_section) (&ei, ".debug_frame");
128 if (!shdr ||
129 (shdr->sh_offset + shdr->sh_size > ei.size))
130 {
131 munmap(ei.image, ei.size);
132 return 1;
133 }
134
135 #if defined(SHF_COMPRESSED)
136 if (shdr->sh_flags & SHF_COMPRESSED)
137 {
138 Elf_W (Chdr) *chdr = (shdr->sh_offset + ei.image);
139 #ifdef HAVE_ZLIB
140 unsigned long destSize;
141 if (chdr->ch_type == ELFCOMPRESS_ZLIB)
142 {
143 *bufsize = destSize = chdr->ch_size;
144
145 GET_MEMORY (*buf, *bufsize);
146 if (!*buf)
147 {
148 Debug (2, "failed to allocate zlib .debug_frame buffer, skipping\n");
149 munmap(ei.image, ei.size);
150 return 1;
151 }
152
153 ret = uncompress((unsigned char *)*buf, &destSize,
154 shdr->sh_offset + ei.image + sizeof(*chdr),
155 shdr->sh_size - sizeof(*chdr));
156 if (ret != Z_OK)
157 {
158 Debug (2, "failed to decompress zlib .debug_frame, skipping\n");
159 munmap(*buf, *bufsize);
160 munmap(ei.image, ei.size);
161 return 1;
162 }
163
164 Debug (4, "read %zd->%zd bytes of .debug_frame from offset %zd\n",
165 shdr->sh_size, *bufsize, shdr->sh_offset);
166 }
167 else
168 #endif /* HAVE_ZLIB */
169 {
170 Debug (2, "unknown compression type %d, skipping\n",
171 chdr->ch_type);
172 munmap(ei.image, ei.size);
173 return 1;
174 }
175 }
176 else
177 {
178 #endif
179 *bufsize = shdr->sh_size;
180
181 GET_MEMORY (*buf, *bufsize);
182 if (!*buf)
183 {
184 Debug (2, "failed to allocate .debug_frame buffer, skipping\n");
185 munmap(ei.image, ei.size);
186 return 1;
187 }
188
189 memcpy(*buf, shdr->sh_offset + ei.image, *bufsize);
190
191 Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
192 *bufsize, shdr->sh_offset);
193 #if defined(SHF_COMPRESSED)
194 }
195 #endif
196
197 ehdr = ei.image;
198 phdr = (Elf_W (Phdr) *) ((char *) ei.image + ehdr->e_phoff);
199
200 for (i = 0; i < ehdr->e_phnum; ++i)
201 if (phdr[i].p_type == PT_LOAD)
202 {
203 *load_offset = segbase - phdr[i].p_vaddr;
204
205 Debug (4, "%s load offset is 0x%zx\n", file, *load_offset);
206
207 break;
208 }
209
210 munmap(ei.image, ei.size);
211 return 0;
212 }
213
214 /* Locate the binary which originated the contents of address ADDR. Return
215 the name of the binary in *name (space is allocated by the caller)
216 Returns 0 if a binary is successfully found, or 1 if an error occurs. */
217
218 static int
find_binary_for_address(unw_word_t ip,char * name,size_t name_size)219 find_binary_for_address (unw_word_t ip, char *name, size_t name_size)
220 {
221 #if defined(__linux__) && (!UNW_REMOTE_ONLY)
222 struct map_iterator mi;
223 int found = 0;
224 int pid = getpid ();
225 unsigned long segbase, mapoff, hi;
226
227 if (maps_init (&mi, pid) != 0)
228 return 1;
229
230 while (maps_next (&mi, &segbase, &hi, &mapoff, NULL))
231 if (ip >= segbase && ip < hi)
232 {
233 size_t len = strlen (mi.path);
234
235 if (len + 1 <= name_size)
236 {
237 memcpy (name, mi.path, len + 1);
238 found = 1;
239 }
240 break;
241 }
242 maps_close (&mi);
243 return !found;
244 #endif
245
246 return 1;
247 }
248
249 /* Locate and/or try to load a debug_frame section for address ADDR. Return
250 pointer to debug frame descriptor, or zero if not found. */
251
252 static struct unw_debug_frame_list *
locate_debug_info(unw_addr_space_t as,unw_word_t addr,unw_word_t segbase,const char * dlname,unw_word_t start,unw_word_t end)253 locate_debug_info (unw_addr_space_t as, unw_word_t addr, unw_word_t segbase,
254 const char *dlname, unw_word_t start, unw_word_t end)
255 {
256 struct unw_debug_frame_list *w, *fdesc = 0;
257 char path[PATH_MAX];
258 char *name = path;
259 int err;
260 char *buf;
261 size_t bufsize;
262 unw_word_t load_offset;
263
264 /* First, see if we loaded this frame already. */
265
266 for (w = as->debug_frames; w; w = w->next)
267 {
268 Debug (4, "checking %p: %lx-%lx\n", w, (long)w->start, (long)w->end);
269 if (addr >= w->start && addr < w->end)
270 return w;
271 }
272
273 /* If the object name we receive is blank, there's still a chance of locating
274 the file by parsing /proc/self/maps. */
275
276 if (strcmp (dlname, "") == 0)
277 {
278 err = find_binary_for_address (addr, name, sizeof(path));
279 if (err)
280 {
281 Debug (15, "tried to locate binary for 0x%" PRIx64 ", but no luck\n",
282 (uint64_t) addr);
283 return 0;
284 }
285 }
286 else
287 name = (char*) dlname;
288
289 err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space,
290 segbase, &load_offset);
291
292 if (!err)
293 {
294 GET_MEMORY (fdesc, sizeof (struct unw_debug_frame_list));
295 if (!fdesc)
296 {
297 Debug (2, "failed to allocate frame list entry\n");
298 return 0;
299 }
300
301 fdesc->start = start;
302 fdesc->end = end;
303 fdesc->load_offset = load_offset;
304 fdesc->debug_frame = buf;
305 fdesc->debug_frame_size = bufsize;
306 fdesc->index = NULL;
307 fdesc->next = as->debug_frames;
308
309 as->debug_frames = fdesc;
310 }
311
312 return fdesc;
313 }
314
315 static size_t
debug_frame_index_make(struct unw_debug_frame_list * fdesc)316 debug_frame_index_make (struct unw_debug_frame_list *fdesc)
317 {
318 unw_accessors_t *a = unw_get_accessors_int (unw_local_addr_space);
319 char *buf = fdesc->debug_frame;
320 size_t bufsize = fdesc->debug_frame_size;
321 unw_word_t addr = (unw_word_t) (uintptr_t) buf;
322 size_t count = 0;
323
324 while (addr < (unw_word_t) (uintptr_t) (buf + bufsize))
325 {
326 unw_word_t item_start = addr, item_end = 0;
327 uint32_t u32val = 0;
328 uint64_t cie_id = 0;
329 uint64_t id_for_cie;
330
331 dwarf_readu32 (unw_local_addr_space, a, &addr, &u32val, NULL);
332
333 if (u32val == 0)
334 break;
335
336 if (u32val != 0xffffffff)
337 {
338 uint32_t cie_id32 = 0;
339
340 item_end = addr + u32val;
341 dwarf_readu32 (unw_local_addr_space, a, &addr, &cie_id32, NULL);
342 cie_id = cie_id32;
343 id_for_cie = 0xffffffff;
344 }
345 else
346 {
347 uint64_t u64val = 0;
348
349 /* Extended length. */
350 dwarf_readu64 (unw_local_addr_space, a, &addr, &u64val, NULL);
351 item_end = addr + u64val;
352
353 dwarf_readu64 (unw_local_addr_space, a, &addr, &cie_id, NULL);
354 id_for_cie = 0xffffffffffffffffull;
355 }
356
357 /*Debug (1, "CIE/FDE id = %.8x\n", (int) cie_id);*/
358
359 if (cie_id == id_for_cie)
360 {
361 ;
362 /*Debug (1, "Found CIE at %.8x.\n", item_start);*/
363 }
364 else
365 {
366 unw_word_t fde_addr = item_start;
367 unw_proc_info_t this_pi;
368 int err;
369
370 /*Debug (1, "Found FDE at %.8x\n", item_start);*/
371
372 err = dwarf_extract_proc_info_from_fde (unw_local_addr_space,
373 a, &fde_addr,
374 &this_pi,
375 (uintptr_t) buf, 0, 1,
376 NULL);
377
378 if (!err)
379 {
380 Debug (15, "start_ip = %lx, end_ip = %lx\n",
381 (long) this_pi.start_ip, (long) this_pi.end_ip);
382
383 if (fdesc->index)
384 {
385 struct table_entry *e = &fdesc->index[count];
386
387 e->fde_offset = item_start - (unw_word_t) (uintptr_t) buf;
388 e->start_ip_offset = this_pi.start_ip;
389 }
390
391 count++;
392 }
393 /*else
394 Debug (1, "FDE parse failed\n");*/
395 }
396
397 addr = item_end;
398 }
399 return count;
400 }
401
402 static void
debug_frame_index_sort(struct unw_debug_frame_list * fdesc)403 debug_frame_index_sort (struct unw_debug_frame_list *fdesc)
404 {
405 size_t i, j, k, n = fdesc->index_size / sizeof (*fdesc->index);
406 struct table_entry *a = fdesc->index;
407 struct table_entry t;
408
409 /* Use a simple Shell sort as it relatively fast and
410 * does not require additional memory. */
411
412 for (k = n / 2; k > 0; k /= 2)
413 {
414 for (i = k; i < n; i++)
415 {
416 t = a[i];
417
418 for (j = i; j >= k; j -= k)
419 {
420 if (t.start_ip_offset >= a[j - k].start_ip_offset)
421 break;
422
423 a[j] = a[j - k];
424 }
425
426 a[j] = t;
427 }
428 }
429 }
430
431 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)432 dwarf_find_debug_frame (int found, unw_dyn_info_t *di_debug, unw_word_t ip,
433 unw_word_t segbase, const char* obj_name,
434 unw_word_t start, unw_word_t end)
435 {
436 unw_dyn_info_t *di = di_debug;
437 struct unw_debug_frame_list *fdesc;
438
439 Debug (15, "Trying to find .debug_frame for %s\n", obj_name);
440
441 fdesc = locate_debug_info (unw_local_addr_space, ip, segbase, obj_name, start,
442 end);
443
444 if (!fdesc)
445 {
446 Debug (15, "couldn't load .debug_frame\n");
447 return found;
448 }
449
450 Debug (15, "loaded .debug_frame\n");
451
452 if (fdesc->debug_frame_size == 0)
453 {
454 Debug (15, "zero-length .debug_frame\n");
455 return found;
456 }
457
458 /* Now create a binary-search table, if it does not already exist. */
459
460 if (!fdesc->index)
461 {
462 /* Find all FDE entries in debug_frame, and make into a sorted
463 index. First determine an index element count. */
464
465 size_t count = debug_frame_index_make (fdesc);
466
467 if (!count)
468 {
469 Debug (15, "no CIE/FDE found in .debug_frame\n");
470 return found;
471 }
472
473 fdesc->index_size = count * sizeof (*fdesc->index);
474 GET_MEMORY (fdesc->index, fdesc->index_size);
475
476 if (!fdesc->index)
477 {
478 Debug (15, "couldn't allocate a frame index table\n");
479 fdesc->index_size = 0;
480 return found;
481 }
482
483 /* Then fill and sort the index. */
484
485 debug_frame_index_make (fdesc);
486 debug_frame_index_sort (fdesc);
487
488 /*for (i = 0; i < count; i++)
489 {
490 const struct table_entry *e = &fdesc->index[i];
491
492 Debug (15, "ip %x, FDE offset %x\n",
493 e->start_ip_offset, e->fde_offset);
494 }*/
495 }
496
497 di->format = UNW_INFO_FORMAT_TABLE;
498 di->start_ip = fdesc->start;
499 di->end_ip = fdesc->end;
500 di->load_offset = fdesc->load_offset;
501 di->u.ti.name_ptr = (unw_word_t) (uintptr_t) obj_name;
502 di->u.ti.table_data = (unw_word_t *) fdesc;
503 di->u.ti.table_len = sizeof (*fdesc) / sizeof (unw_word_t);
504 di->u.ti.segbase = segbase;
505
506 found = 1;
507 Debug (15, "found debug_frame table `%s': segbase=0x%lx, len=%lu, "
508 "gp=0x%lx, table_data=0x%lx\n",
509 (char *) (uintptr_t) di->u.ti.name_ptr,
510 (long) di->u.ti.segbase, (long) di->u.ti.table_len,
511 (long) di->gp, (long) di->u.ti.table_data);
512
513 return found;
514 }
515
516 #endif /* CONFIG_DEBUG_FRAME */
517
518 #ifndef UNW_REMOTE_ONLY
519
520 static Elf_W (Addr)
dwarf_find_eh_frame_section(struct dl_phdr_info * info)521 dwarf_find_eh_frame_section(struct dl_phdr_info *info)
522 {
523 int rc;
524 struct elf_image ei;
525 Elf_W (Addr) eh_frame = 0;
526 Elf_W (Shdr)* shdr;
527 const char *file = info->dlpi_name;
528 char exepath[PATH_MAX];
529
530 if (strlen(file) == 0)
531 {
532 tdep_get_exe_image_path(exepath);
533 file = exepath;
534 }
535
536 Debug (1, "looking for .eh_frame section in %s\n",
537 file);
538
539 rc = elf_map_image (&ei, file);
540 if (rc != 0)
541 return 0;
542
543 shdr = elf_w (find_section) (&ei, ".eh_frame");
544 if (!shdr)
545 goto out;
546
547 eh_frame = shdr->sh_addr + info->dlpi_addr;
548 Debug (4, "found .eh_frame at address %lx\n",
549 eh_frame);
550
551 out:
552 munmap (ei.image, ei.size);
553
554 return eh_frame;
555 }
556
557 struct dwarf_callback_data
558 {
559 /* in: */
560 unw_word_t ip; /* instruction-pointer we're looking for */
561 unw_proc_info_t *pi; /* proc-info pointer */
562 int need_unwind_info;
563 /* out: */
564 int single_fde; /* did we find a single FDE? (vs. a table) */
565 unw_dyn_info_t di; /* table info (if single_fde is false) */
566 unw_dyn_info_t di_debug; /* additional table info for .debug_frame */
567 };
568
569 /* ptr is a pointer to a dwarf_callback_data structure and, on entry,
570 member ip contains the instruction-pointer we're looking
571 for. */
572 HIDDEN int
dwarf_callback(struct dl_phdr_info * info,size_t size,void * ptr)573 dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
574 {
575 struct dwarf_callback_data *cb_data = ptr;
576 unw_dyn_info_t *di = &cb_data->di;
577 const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
578 unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
579 Elf_W(Addr) load_base, max_load_addr = 0;
580 int ret, need_unwind_info = cb_data->need_unwind_info;
581 unw_proc_info_t *pi = cb_data->pi;
582 struct dwarf_eh_frame_hdr *hdr = NULL;
583 unw_accessors_t *a;
584 long n;
585 int found = 0;
586 struct dwarf_eh_frame_hdr synth_eh_frame_hdr;
587 #ifdef CONFIG_DEBUG_FRAME
588 unw_word_t start, end;
589 #endif /* CONFIG_DEBUG_FRAME*/
590
591 ip = cb_data->ip;
592
593 /* Make sure struct dl_phdr_info is at least as big as we need. */
594 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
595 + sizeof (info->dlpi_phnum))
596 return -1;
597
598 Debug (15, "checking %s, base=0x%lx)\n",
599 info->dlpi_name, (long) info->dlpi_addr);
600
601 phdr = info->dlpi_phdr;
602 load_base = info->dlpi_addr;
603 p_text = NULL;
604 p_eh_hdr = NULL;
605 p_dynamic = NULL;
606
607 /* See if PC falls into one of the loaded segments. Find the
608 eh-header segment at the same time. */
609 for (n = info->dlpi_phnum; --n >= 0; phdr++)
610 {
611 if (phdr->p_type == PT_LOAD)
612 {
613 Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
614
615 if (ip >= vaddr && ip < vaddr + phdr->p_memsz)
616 p_text = phdr;
617
618 if (vaddr + phdr->p_filesz > max_load_addr)
619 max_load_addr = vaddr + phdr->p_filesz;
620 }
621 else if (phdr->p_type == PT_GNU_EH_FRAME)
622 p_eh_hdr = phdr;
623 #if defined __sun
624 else if (phdr->p_type == PT_SUNW_UNWIND)
625 p_eh_hdr = phdr;
626 #endif
627 else if (phdr->p_type == PT_DYNAMIC)
628 p_dynamic = phdr;
629 }
630
631 if (!p_text)
632 return 0;
633
634 if (p_eh_hdr)
635 {
636 hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
637 }
638 else
639 {
640 Elf_W (Addr) eh_frame;
641 Debug (1, "no .eh_frame_hdr section found\n");
642 eh_frame = dwarf_find_eh_frame_section (info);
643 if (eh_frame)
644 {
645 Debug (1, "using synthetic .eh_frame_hdr section for %s\n",
646 info->dlpi_name);
647 synth_eh_frame_hdr.version = DW_EH_VERSION;
648 synth_eh_frame_hdr.eh_frame_ptr_enc = DW_EH_PE_absptr |
649 ((sizeof(Elf_W (Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8);
650 synth_eh_frame_hdr.fde_count_enc = DW_EH_PE_omit;
651 synth_eh_frame_hdr.table_enc = DW_EH_PE_omit;
652 synth_eh_frame_hdr.eh_frame = eh_frame;
653 hdr = &synth_eh_frame_hdr;
654 }
655 }
656
657 if (hdr)
658 {
659 if (p_dynamic)
660 {
661 /* For dynamically linked executables and shared libraries,
662 DT_PLTGOT is the value that data-relative addresses are
663 relative to for that object. We call this the "gp". */
664 Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
665 for (; dyn->d_tag != DT_NULL; ++dyn)
666 if (dyn->d_tag == DT_PLTGOT)
667 {
668 /* Assume that _DYNAMIC is writable and GLIBC has
669 relocated it (true for x86 at least). */
670 di->gp = dyn->d_un.d_ptr;
671 break;
672 }
673 }
674 else
675 /* Otherwise this is a static executable with no _DYNAMIC. Assume
676 that data-relative addresses are relative to 0, i.e.,
677 absolute. */
678 di->gp = 0;
679 pi->gp = di->gp;
680
681 if (hdr->version != DW_EH_VERSION)
682 {
683 Debug (1, "table `%s' has unexpected version %d\n",
684 info->dlpi_name, hdr->version);
685 return 0;
686 }
687
688 a = unw_get_accessors_int (unw_local_addr_space);
689 addr = (unw_word_t) (uintptr_t) (&hdr->eh_frame);
690
691 /* (Optionally) read eh_frame_ptr: */
692 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
693 &addr, hdr->eh_frame_ptr_enc, pi,
694 &eh_frame_start, NULL)) < 0)
695 return ret;
696
697 /* (Optionally) read fde_count: */
698 if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
699 &addr, hdr->fde_count_enc, pi,
700 &fde_count, NULL)) < 0)
701 return ret;
702
703 if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
704 {
705 /* If there is no search table or it has an unsupported
706 encoding, fall back on linear search. */
707 if (hdr->table_enc == DW_EH_PE_omit)
708 {
709 Debug (4, "table `%s' lacks search table; doing linear search\n",
710 info->dlpi_name);
711 }
712 else
713 {
714 Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
715 info->dlpi_name, hdr->table_enc);
716 }
717
718 eh_frame_end = max_load_addr; /* XXX can we do better? */
719
720 if (hdr->fde_count_enc == DW_EH_PE_omit)
721 fde_count = ~0UL;
722 if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
723 abort ();
724
725 Debug (1, "eh_frame_start = %lx eh_frame_end = %lx\n",
726 eh_frame_start, eh_frame_end);
727
728 /* XXX we know how to build a local binary search table for
729 .debug_frame, so we could do that here too. */
730 found = linear_search (unw_local_addr_space, ip,
731 eh_frame_start, eh_frame_end, fde_count,
732 pi, need_unwind_info, NULL);
733 if (found != 1)
734 found = 0;
735 else
736 cb_data->single_fde = 1;
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 if (cb_data.single_fde)
813 /* already got the result in *pi */
814 return 0;
815
816 /* search the table: */
817 if (cb_data.di.format != -1)
818 ret = dwarf_search_unwind_table_int (as, ip, &cb_data.di,
819 pi, need_unwind_info, arg);
820 else
821 ret = -UNW_ENOINFO;
822
823 if (ret == -UNW_ENOINFO && cb_data.di_debug.format != -1)
824 ret = dwarf_search_unwind_table_int (as, ip, &cb_data.di_debug, pi,
825 need_unwind_info, arg);
826 }
827 else
828 ret = -UNW_ENOINFO;
829
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,int32_t * last_ip_offset,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, int32_t *last_ip_offset, void *arg)
868 {
869 size_t table_len = table_size / sizeof (struct table_entry);
870 unw_accessors_t *a = unw_get_accessors_int (as);
871 size_t lo, hi, mid;
872 unw_word_t e_addr = 0;
873 int32_t start = 0;
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 || (hi < table_len &&
895 (ret = dwarf_reads32 (as, a, &e_addr, last_ip_offset, arg)) < 0))
896 return ret;
897 return 1;
898 }
899
900 #endif /* !UNW_LOCAL_ONLY */
901
is_remote_table(int format)902 static int is_remote_table(int format)
903 {
904 return (format == UNW_INFO_FORMAT_REMOTE_TABLE ||
905 format == UNW_INFO_FORMAT_IP_OFFSET);
906 }
907
908 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)909 dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
910 unw_dyn_info_t *di, unw_proc_info_t *pi,
911 int need_unwind_info, void *arg)
912 {
913 const struct table_entry *e = NULL, *table = NULL;
914 unw_word_t ip_base = 0, segbase = 0, last_ip, fde_addr;
915 unw_accessors_t *a;
916 #ifndef UNW_LOCAL_ONLY
917 struct table_entry ent;
918 #endif
919 int ret;
920 unw_word_t debug_frame_base = 0;
921 size_t table_len = 0;
922
923 #ifdef UNW_REMOTE_ONLY
924 assert (is_remote_table(di->format));
925 #else
926 assert (is_remote_table(di->format)
927 || di->format == UNW_INFO_FORMAT_TABLE);
928 #endif
929 assert (ip >= di->start_ip && ip < di->end_ip);
930
931 if (is_remote_table(di->format))
932 {
933 table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
934 table_len = di->u.rti.table_len * sizeof (unw_word_t);
935 debug_frame_base = 0;
936 }
937 else
938 {
939 assert(di->format == UNW_INFO_FORMAT_TABLE);
940 #ifndef UNW_REMOTE_ONLY
941 struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
942
943 /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
944 space. Both the index and the unwind tables live in local memory, but
945 the address space to check for properties like the address size and
946 endianness is the target one. */
947 as = unw_local_addr_space;
948 table = fdesc->index;
949 table_len = fdesc->index_size;
950 debug_frame_base = (uintptr_t) fdesc->debug_frame;
951 #endif
952 }
953
954 a = unw_get_accessors_int (as);
955
956 segbase = di->u.rti.segbase;
957 if (di->format == UNW_INFO_FORMAT_IP_OFFSET) {
958 ip_base = di->start_ip;
959 } else {
960 ip_base = segbase;
961 }
962
963 Debug (6, "lookup IP 0x%lx\n", (long) (ip - ip_base - di->load_offset));
964
965 #ifndef UNW_REMOTE_ONLY
966 if (as == unw_local_addr_space)
967 {
968 e = lookup (table, table_len, ip - ip_base - di->load_offset);
969 if (e && &e[1] < &table[table_len / sizeof (unw_word_t)])
970 last_ip = e[1].start_ip_offset + ip_base + di->load_offset;
971 else
972 last_ip = di->end_ip;
973 }
974 else
975 #endif
976 {
977 #ifndef UNW_LOCAL_ONLY
978 int32_t last_ip_offset = di->end_ip - ip_base - di->load_offset;
979 segbase = di->u.rti.segbase;
980 if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
981 ip - ip_base, &ent, &last_ip_offset, arg)) < 0)
982 return ret;
983 if (ret)
984 {
985 e = &ent;
986 last_ip = last_ip_offset + ip_base + di->load_offset;
987 }
988 else
989 e = NULL; /* no info found */
990 #endif
991 }
992 if (!e)
993 {
994 Debug (1, "IP %lx inside range %lx-%lx, but no explicit unwind info found\n",
995 (long) ip, (long) di->start_ip, (long) di->end_ip);
996 /* IP is inside this table's range, but there is no explicit
997 unwind info. */
998 return -UNW_ENOINFO;
999 }
1000 Debug (15, "ip=0x%lx, load_offset=0x%lx, start_ip=0x%lx\n",
1001 (long) ip, (long) di->load_offset, (long) (e->start_ip_offset));
1002 if (debug_frame_base)
1003 fde_addr = e->fde_offset + debug_frame_base;
1004 else
1005 fde_addr = e->fde_offset + segbase;
1006 Debug (1, "e->fde_offset = %lx, segbase = %lx, debug_frame_base = %lx, "
1007 "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
1008 (long) debug_frame_base, (long) fde_addr);
1009 if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
1010 debug_frame_base ?
1011 debug_frame_base : segbase,
1012 need_unwind_info,
1013 debug_frame_base != 0, arg)) < 0)
1014 return ret;
1015
1016 /* .debug_frame uses an absolute encoding that does not know about any
1017 shared library relocation. */
1018 if (di->format == UNW_INFO_FORMAT_TABLE)
1019 {
1020 pi->start_ip += segbase;
1021 pi->end_ip += segbase;
1022 pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
1023 }
1024
1025 pi->start_ip += di->load_offset;
1026 pi->end_ip += di->load_offset;
1027
1028 #if defined(NEED_LAST_IP)
1029 pi->last_ip = last_ip;
1030 #else
1031 (void)last_ip;
1032 #endif
1033 if (ip < pi->start_ip || ip >= pi->end_ip)
1034 return -UNW_ENOINFO;
1035
1036 return 0;
1037 }
1038
1039 HIDDEN void
dwarf_put_unwind_info(unw_addr_space_t as,unw_proc_info_t * pi,void * arg)1040 dwarf_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
1041 {
1042 return; /* always a nop */
1043 }
1044